diff options
| author | Ingo Molnar <mingo@kernel.org> | 2013-01-25 05:33:41 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-01-25 05:34:00 -0500 |
| commit | a2d28d0c198b65fac28ea6212f5f8edc77b29c27 (patch) | |
| tree | 130c1b4464f1eb685e56ff2ce122e3e36bb52e88 | |
| parent | 203e04c16330c880538588e932743f404ee4fd66 (diff) | |
| parent | 2ae828786c65ab8f587647bd0f22f8fe00f1f238 (diff) | |
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:
. Allow skipping problematic entries in 'perf test'.
. Fix some namespace problems in the event parsing routines.
. Add 'perf test' entry to make sure the python binding doesn't have
linking problems.
. Adjust 'perf test' attr tests verbosity levels.
. Make tools/perf build with GNU make v3.80, fix from Al Cooper.
. Do missing feature fallbacks in just one place, removing duplicated
code in multiple tools.
. Fix some memory leaks, from David Ahern.
. Fix segfault when drawing out-of-bounds jumps, from Frederik Deweerdt.
. Allow of casting an array of char to string in 'perf probe', from
Hyeoncheol Lee.
. Add support for wildcard in tracepoint system name, from Jiri Olsa.
. Update FSF postal address to be URL's, from Jon Stanley.
. Add anonymous huge page recognition, from Joshua Zhu.
. Remove some needless feature test checks, from Namhyung Kim.
. Multiple improvements to the sort routines, from Namhyung Kim.
. Fix warning on '>=' operator in libtraceevent, from Namhyung Kim.
. Use ARRAY_SIZE instead of reinventing it in 'perf script' and 'perf kmem',
from Sasha Levin.
. Remove some redundant checks, from Sasha Levin.
. Test correct variable after allocation in libtraceevent, fix from Sasha Levin.
. Mark branch_info maps as referenced, fix from Stephane Eranian.
. Fix PMU format parsing test failure, from Sukadev Bhattiprolu.
. Fix possible (unlikely) buffer overflow, from Thomas Jarosch.
. Multiple 'perf script' fixes, from Tom Zanussi.
. Add missing field in PERF_RECORD_SAMPLE documentation, from Vince Weaver.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
81 files changed, 1816 insertions, 1202 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 4f63c05d27c9..9fa9c622a7f4 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h | |||
| @@ -579,7 +579,8 @@ enum perf_event_type { | |||
| 579 | * { u32 size; | 579 | * { u32 size; |
| 580 | * char data[size];}&& PERF_SAMPLE_RAW | 580 | * char data[size];}&& PERF_SAMPLE_RAW |
| 581 | * | 581 | * |
| 582 | * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK | 582 | * { u64 nr; |
| 583 | * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK | ||
| 583 | * | 584 | * |
| 584 | * { u64 abi; # enum perf_sample_regs_abi | 585 | * { u64 abi; # enum perf_sample_regs_abi |
| 585 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER | 586 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index dea7acfbb071..30ea9a4f4ab4 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
| @@ -901,8 +901,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume | |||
| 901 | } | 901 | } |
| 902 | 902 | ||
| 903 | mutex_unlock(uprobes_hash(inode)); | 903 | mutex_unlock(uprobes_hash(inode)); |
| 904 | if (uprobe) | 904 | put_uprobe(uprobe); |
| 905 | put_uprobe(uprobe); | ||
| 906 | } | 905 | } |
| 907 | 906 | ||
| 908 | static struct rb_node * | 907 | static struct rb_node * |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 5a824e355d04..bb8b3db0e583 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
| 16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | * | 17 | * |
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | * | 19 | * |
| @@ -1463,7 +1462,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
| 1463 | if (read_expect_type(EVENT_ITEM, &token)) | 1462 | if (read_expect_type(EVENT_ITEM, &token)) |
| 1464 | goto fail; | 1463 | goto fail; |
| 1465 | 1464 | ||
| 1466 | /* add signed type */ | 1465 | if (strtoul(token, NULL, 0)) |
| 1466 | field->flags |= FIELD_IS_SIGNED; | ||
| 1467 | 1467 | ||
| 1468 | free_token(token); | 1468 | free_token(token); |
| 1469 | if (read_expected(EVENT_OP, ";") < 0) | 1469 | if (read_expected(EVENT_OP, ";") < 0) |
| @@ -1785,6 +1785,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok) | |||
| 1785 | strcmp(token, "/") == 0 || | 1785 | strcmp(token, "/") == 0 || |
| 1786 | strcmp(token, "<") == 0 || | 1786 | strcmp(token, "<") == 0 || |
| 1787 | strcmp(token, ">") == 0 || | 1787 | strcmp(token, ">") == 0 || |
| 1788 | strcmp(token, "<=") == 0 || | ||
| 1789 | strcmp(token, ">=") == 0 || | ||
| 1788 | strcmp(token, "==") == 0 || | 1790 | strcmp(token, "==") == 0 || |
| 1789 | strcmp(token, "!=") == 0) { | 1791 | strcmp(token, "!=") == 0) { |
| 1790 | 1792 | ||
| @@ -2481,7 +2483,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** | |||
| 2481 | 2483 | ||
| 2482 | free_token(token); | 2484 | free_token(token); |
| 2483 | arg = alloc_arg(); | 2485 | arg = alloc_arg(); |
| 2484 | if (!field) { | 2486 | if (!arg) { |
| 2485 | do_warning("%s: not enough memory!", __func__); | 2487 | do_warning("%s: not enough memory!", __func__); |
| 2486 | *tok = NULL; | 2488 | *tok = NULL; |
| 2487 | return EVENT_ERROR; | 2489 | return EVENT_ERROR; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 24a4bbabc5d5..7be7e89533e4 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
| 16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | * | 17 | * |
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index bc075006966e..e76c9acb92cd 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
| 16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | * | 17 | * |
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 5ea4326ad11f..2500e75583fc 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
| 16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | * | 17 | * |
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index f023a133abb6..bba701cf10e6 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c | |||
| @@ -1,3 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 1 | #include <stdio.h> | 20 | #include <stdio.h> |
| 2 | #include <stdlib.h> | 21 | #include <stdlib.h> |
| 3 | #include <string.h> | 22 | #include <string.h> |
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index b1ccc923e8a5..a57db805136a 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
| 14 | * | 14 | * |
| 15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
| 16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | * | 17 | * |
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 19 | */ |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index f4d91bebd59d..848a0dcb6dfd 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
| @@ -57,11 +57,44 @@ OPTIONS | |||
| 57 | 57 | ||
| 58 | -s:: | 58 | -s:: |
| 59 | --sort=:: | 59 | --sort=:: |
| 60 | Sort by key(s): pid, comm, dso, symbol, parent, srcline. | 60 | Sort histogram entries by given key(s) - multiple keys can be specified |
| 61 | in CSV format. Following sort keys are available: | ||
| 62 | pid, comm, dso, symbol, parent, cpu, srcline. | ||
| 63 | |||
| 64 | Each key has following meaning: | ||
| 65 | |||
| 66 | - comm: command (name) of the task which can be read via /proc/<pid>/comm | ||
| 67 | - pid: command and tid of the task | ||
| 68 | - dso: name of library or module executed at the time of sample | ||
| 69 | - symbol: name of function executed at the time of sample | ||
| 70 | - parent: name of function matched to the parent regex filter. Unmatched | ||
| 71 | entries are displayed as "[other]". | ||
| 72 | - cpu: cpu number the task ran at the time of sample | ||
| 73 | - srcline: filename and line number executed at the time of sample. The | ||
| 74 | DWARF debuggin info must be provided. | ||
| 75 | |||
| 76 | By default, comm, dso and symbol keys are used. | ||
| 77 | (i.e. --sort comm,dso,symbol) | ||
| 78 | |||
| 79 | If --branch-stack option is used, following sort keys are also | ||
| 80 | available: | ||
| 81 | dso_from, dso_to, symbol_from, symbol_to, mispredict. | ||
| 82 | |||
| 83 | - dso_from: name of library or module branched from | ||
| 84 | - dso_to: name of library or module branched to | ||
| 85 | - symbol_from: name of function branched from | ||
| 86 | - symbol_to: name of function branched to | ||
| 87 | - mispredict: "N" for predicted branch, "Y" for mispredicted branch | ||
| 88 | |||
| 89 | And default sort keys are changed to comm, dso_from, symbol_from, dso_to | ||
| 90 | and symbol_to, see '--branch-stack'. | ||
| 61 | 91 | ||
| 62 | -p:: | 92 | -p:: |
| 63 | --parent=<regex>:: | 93 | --parent=<regex>:: |
| 64 | regex filter to identify parent, see: '--sort parent' | 94 | A regex filter to identify parent. The parent is a caller of this |
| 95 | function and searched through the callchain, thus it requires callchain | ||
| 96 | information recorded. The pattern is in the exteneded regex format and | ||
| 97 | defaults to "\^sys_|^do_page_fault", see '--sort parent'. | ||
| 65 | 98 | ||
| 66 | -x:: | 99 | -x:: |
| 67 | --exclude-other:: | 100 | --exclude-other:: |
| @@ -74,7 +107,6 @@ OPTIONS | |||
| 74 | 107 | ||
| 75 | -t:: | 108 | -t:: |
| 76 | --field-separator=:: | 109 | --field-separator=:: |
| 77 | |||
| 78 | Use a special separator character and don't pad with spaces, replacing | 110 | Use a special separator character and don't pad with spaces, replacing |
| 79 | all occurrences of this separator in symbol names (and other output) | 111 | all occurrences of this separator in symbol names (and other output) |
| 80 | with a '.' character, that thus it's the only non valid separator. | 112 | with a '.' character, that thus it's the only non valid separator. |
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index a4027f221a53..9f1f054b8432 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt | |||
| @@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.: | |||
| 336 | ---- | 336 | ---- |
| 337 | root@tropicana:~# perf script -l | 337 | root@tropicana:~# perf script -l |
| 338 | List of available trace scripts: | 338 | List of available trace scripts: |
| 339 | workqueue-stats workqueue stats (ins/exe/create/destroy) | ||
| 340 | wakeup-latency system-wide min/max/avg wakeup latency | 339 | wakeup-latency system-wide min/max/avg wakeup latency |
| 341 | rw-by-file <comm> r/w activity for a program, by file | 340 | rw-by-file <comm> r/w activity for a program, by file |
| 342 | rw-by-pid system-wide r/w activity | 341 | rw-by-pid system-wide r/w activity |
| @@ -402,7 +401,6 @@ should show a new entry for your script: | |||
| 402 | ---- | 401 | ---- |
| 403 | root@tropicana:~# perf script -l | 402 | root@tropicana:~# perf script -l |
| 404 | List of available trace scripts: | 403 | List of available trace scripts: |
| 405 | workqueue-stats workqueue stats (ins/exe/create/destroy) | ||
| 406 | wakeup-latency system-wide min/max/avg wakeup latency | 404 | wakeup-latency system-wide min/max/avg wakeup latency |
| 407 | rw-by-file <comm> r/w activity for a program, by file | 405 | rw-by-file <comm> r/w activity for a program, by file |
| 408 | rw-by-pid system-wide r/w activity | 406 | rw-by-pid system-wide r/w activity |
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index b24ac40fcd58..d1d3e5121f89 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt | |||
| @@ -23,6 +23,10 @@ from 'perf test list'. | |||
| 23 | 23 | ||
| 24 | OPTIONS | 24 | OPTIONS |
| 25 | ------- | 25 | ------- |
| 26 | -s:: | ||
| 27 | --skip:: | ||
| 28 | Tests to skip (comma separater numeric list). | ||
| 29 | |||
| 26 | -v:: | 30 | -v:: |
| 27 | --verbose:: | 31 | --verbose:: |
| 28 | Be more verbose. | 32 | Be more verbose. |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2cbaad83a6e2..a84021abb3fe 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -50,7 +50,6 @@ include config/utilities.mak | |||
| 50 | 50 | ||
| 51 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 51 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
| 52 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 52 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
| 53 | -include $(OUTPUT)PERF-VERSION-FILE | ||
| 54 | 53 | ||
| 55 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 54 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
| 56 | 55 | ||
| @@ -487,6 +486,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o | |||
| 487 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 486 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
| 488 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 487 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
| 489 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 488 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
| 489 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | ||
| 490 | LIB_OBJS += $(OUTPUT)tests/python-use.o | ||
| 490 | 491 | ||
| 491 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 492 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
| 492 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 493 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
| @@ -532,9 +533,6 @@ ifneq ($(MAKECMDGOALS),tags) | |||
| 532 | # because maintaining the nesting to match is a pain. If | 533 | # because maintaining the nesting to match is a pain. If |
| 533 | # we had "elif" things would have been much nicer... | 534 | # we had "elif" things would have been much nicer... |
| 534 | 535 | ||
| 535 | -include config.mak.autogen | ||
| 536 | -include config.mak | ||
| 537 | |||
| 538 | ifdef NO_LIBELF | 536 | ifdef NO_LIBELF |
| 539 | NO_DWARF := 1 | 537 | NO_DWARF := 1 |
| 540 | NO_DEMANGLE := 1 | 538 | NO_DEMANGLE := 1 |
| @@ -686,6 +684,7 @@ ifndef NO_GTK2 | |||
| 686 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | 684 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) |
| 687 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | 685 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) |
| 688 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | 686 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o |
| 687 | LIB_OBJS += $(OUTPUT)ui/gtk/hists.o | ||
| 689 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o | 688 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o |
| 690 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | 689 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o |
| 691 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | 690 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o |
| @@ -887,7 +886,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf | |||
| 887 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf | 886 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf |
| 888 | 887 | ||
| 889 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS | 888 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
| 890 | $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ | 889 | $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ |
| 891 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 890 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
| 892 | $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ | 891 | $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ |
| 893 | 892 | ||
| @@ -951,7 +950,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS | |||
| 951 | 950 | ||
| 952 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS | 951 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS |
| 953 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | 952 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ |
| 954 | '-DBINDIR="$(bindir_SQ)"' \ | 953 | '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ |
| 954 | $< | ||
| 955 | |||
| 956 | $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS | ||
| 957 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | ||
| 958 | -DPYTHONPATH='"$(OUTPUT)python"' \ | ||
| 959 | -DPYTHON='"$(PYTHON_WORD)"' \ | ||
| 955 | $< | 960 | $< |
| 956 | 961 | ||
| 957 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS | 962 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS |
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index cae9a5fd2ecf..afd1255a632f 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c | |||
| @@ -159,6 +159,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ | |||
| 159 | printf("# Running %s/%s benchmark...\n", | 159 | printf("# Running %s/%s benchmark...\n", |
| 160 | subsys->name, | 160 | subsys->name, |
| 161 | suites[i].name); | 161 | suites[i].name); |
| 162 | fflush(stdout); | ||
| 162 | 163 | ||
| 163 | argv[1] = suites[i].name; | 164 | argv[1] = suites[i].name; |
| 164 | suites[i].fn(1, argv, NULL); | 165 | suites[i].fn(1, argv, NULL); |
| @@ -225,6 +226,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 225 | printf("# Running %s/%s benchmark...\n", | 226 | printf("# Running %s/%s benchmark...\n", |
| 226 | subsystems[i].name, | 227 | subsystems[i].name, |
| 227 | subsystems[i].suites[j].name); | 228 | subsystems[i].suites[j].name); |
| 229 | fflush(stdout); | ||
| 228 | status = subsystems[i].suites[j].fn(argc - 1, | 230 | status = subsystems[i].suites[j].fn(argc - 1, |
| 229 | argv + 1, prefix); | 231 | argv + 1, prefix); |
| 230 | goto end; | 232 | goto end; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b2e7d39f099b..4af0b580b046 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -275,43 +275,6 @@ static struct perf_tool tool = { | |||
| 275 | .ordering_requires_timestamps = true, | 275 | .ordering_requires_timestamps = true, |
| 276 | }; | 276 | }; |
| 277 | 277 | ||
| 278 | static void insert_hist_entry_by_name(struct rb_root *root, | ||
| 279 | struct hist_entry *he) | ||
| 280 | { | ||
| 281 | struct rb_node **p = &root->rb_node; | ||
| 282 | struct rb_node *parent = NULL; | ||
| 283 | struct hist_entry *iter; | ||
| 284 | |||
| 285 | while (*p != NULL) { | ||
| 286 | parent = *p; | ||
| 287 | iter = rb_entry(parent, struct hist_entry, rb_node); | ||
| 288 | if (hist_entry__cmp(he, iter) < 0) | ||
| 289 | p = &(*p)->rb_left; | ||
| 290 | else | ||
| 291 | p = &(*p)->rb_right; | ||
| 292 | } | ||
| 293 | |||
| 294 | rb_link_node(&he->rb_node, parent, p); | ||
| 295 | rb_insert_color(&he->rb_node, root); | ||
| 296 | } | ||
| 297 | |||
| 298 | static void hists__name_resort(struct hists *self) | ||
| 299 | { | ||
| 300 | struct rb_root tmp = RB_ROOT; | ||
| 301 | struct rb_node *next = rb_first(&self->entries); | ||
| 302 | |||
| 303 | while (next != NULL) { | ||
| 304 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); | ||
| 305 | |||
| 306 | next = rb_next(&n->rb_node); | ||
| 307 | |||
| 308 | rb_erase(&n->rb_node, &self->entries); | ||
| 309 | insert_hist_entry_by_name(&tmp, n); | ||
| 310 | } | ||
| 311 | |||
| 312 | self->entries = tmp; | ||
| 313 | } | ||
| 314 | |||
| 315 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | 278 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, |
| 316 | struct perf_evlist *evlist) | 279 | struct perf_evlist *evlist) |
| 317 | { | 280 | { |
| @@ -324,30 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | |||
| 324 | return NULL; | 287 | return NULL; |
| 325 | } | 288 | } |
| 326 | 289 | ||
| 327 | static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) | 290 | static void perf_evlist__collapse_resort(struct perf_evlist *evlist) |
| 328 | { | 291 | { |
| 329 | struct perf_evsel *evsel; | 292 | struct perf_evsel *evsel; |
| 330 | 293 | ||
| 331 | list_for_each_entry(evsel, &evlist->entries, node) { | 294 | list_for_each_entry(evsel, &evlist->entries, node) { |
| 332 | struct hists *hists = &evsel->hists; | 295 | struct hists *hists = &evsel->hists; |
| 333 | 296 | ||
| 334 | hists__output_resort(hists); | 297 | hists__collapse_resort(hists); |
| 335 | |||
| 336 | if (name) | ||
| 337 | hists__name_resort(hists); | ||
| 338 | } | 298 | } |
| 339 | } | 299 | } |
| 340 | 300 | ||
| 341 | static void hists__baseline_only(struct hists *hists) | 301 | static void hists__baseline_only(struct hists *hists) |
| 342 | { | 302 | { |
| 343 | struct rb_node *next = rb_first(&hists->entries); | 303 | struct rb_root *root; |
| 304 | struct rb_node *next; | ||
| 305 | |||
| 306 | if (sort__need_collapse) | ||
| 307 | root = &hists->entries_collapsed; | ||
| 308 | else | ||
| 309 | root = hists->entries_in; | ||
| 344 | 310 | ||
| 311 | next = rb_first(root); | ||
| 345 | while (next != NULL) { | 312 | while (next != NULL) { |
| 346 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 313 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); |
| 347 | 314 | ||
| 348 | next = rb_next(&he->rb_node); | 315 | next = rb_next(&he->rb_node_in); |
| 349 | if (!hist_entry__next_pair(he)) { | 316 | if (!hist_entry__next_pair(he)) { |
| 350 | rb_erase(&he->rb_node, &hists->entries); | 317 | rb_erase(&he->rb_node_in, root); |
| 351 | hist_entry__free(he); | 318 | hist_entry__free(he); |
| 352 | } | 319 | } |
| 353 | } | 320 | } |
| @@ -447,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root, | |||
| 447 | 414 | ||
| 448 | static void hists__compute_resort(struct hists *hists) | 415 | static void hists__compute_resort(struct hists *hists) |
| 449 | { | 416 | { |
| 450 | struct rb_root tmp = RB_ROOT; | 417 | struct rb_root *root; |
| 451 | struct rb_node *next = rb_first(&hists->entries); | 418 | struct rb_node *next; |
| 419 | |||
| 420 | if (sort__need_collapse) | ||
| 421 | root = &hists->entries_collapsed; | ||
| 422 | else | ||
| 423 | root = hists->entries_in; | ||
| 424 | |||
| 425 | hists->entries = RB_ROOT; | ||
| 426 | next = rb_first(root); | ||
| 427 | |||
| 428 | hists->nr_entries = 0; | ||
| 429 | hists->stats.total_period = 0; | ||
| 430 | hists__reset_col_len(hists); | ||
| 452 | 431 | ||
| 453 | while (next != NULL) { | 432 | while (next != NULL) { |
| 454 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 433 | struct hist_entry *he; |
| 455 | 434 | ||
| 456 | next = rb_next(&he->rb_node); | 435 | he = rb_entry(next, struct hist_entry, rb_node_in); |
| 436 | next = rb_next(&he->rb_node_in); | ||
| 457 | 437 | ||
| 458 | rb_erase(&he->rb_node, &hists->entries); | 438 | insert_hist_entry_by_compute(&hists->entries, he, compute); |
| 459 | insert_hist_entry_by_compute(&tmp, he, compute); | 439 | hists__inc_nr_entries(hists, he); |
| 460 | } | 440 | } |
| 461 | |||
| 462 | hists->entries = tmp; | ||
| 463 | } | 441 | } |
| 464 | 442 | ||
| 465 | static void hists__process(struct hists *old, struct hists *new) | 443 | static void hists__process(struct hists *old, struct hists *new) |
| @@ -474,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new) | |||
| 474 | if (sort_compute) { | 452 | if (sort_compute) { |
| 475 | hists__precompute(new); | 453 | hists__precompute(new); |
| 476 | hists__compute_resort(new); | 454 | hists__compute_resort(new); |
| 455 | } else { | ||
| 456 | hists__output_resort(new); | ||
| 477 | } | 457 | } |
| 478 | 458 | ||
| 479 | hists__fprintf(new, true, 0, 0, stdout); | 459 | hists__fprintf(new, true, 0, 0, stdout); |
| @@ -505,8 +485,8 @@ static int __cmd_diff(void) | |||
| 505 | evlist_old = older->evlist; | 485 | evlist_old = older->evlist; |
| 506 | evlist_new = newer->evlist; | 486 | evlist_new = newer->evlist; |
| 507 | 487 | ||
| 508 | perf_evlist__resort_hists(evlist_old, true); | 488 | perf_evlist__collapse_resort(evlist_old); |
| 509 | perf_evlist__resort_hists(evlist_new, false); | 489 | perf_evlist__collapse_resort(evlist_new); |
| 510 | 490 | ||
| 511 | list_for_each_entry(evsel, &evlist_new->entries, node) { | 491 | list_for_each_entry(evsel, &evlist_new->entries, node) { |
| 512 | struct perf_evsel *evsel_old; | 492 | struct perf_evsel *evsel_old; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0b4b796167be..c746108c5d48 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -340,7 +340,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
| 340 | int n_lines, int is_caller) | 340 | int n_lines, int is_caller) |
| 341 | { | 341 | { |
| 342 | struct rb_node *next; | 342 | struct rb_node *next; |
| 343 | struct machine *machine; | 343 | struct machine *machine = &session->machines.host; |
| 344 | 344 | ||
| 345 | printf("%.102s\n", graph_dotted_line); | 345 | printf("%.102s\n", graph_dotted_line); |
| 346 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); | 346 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); |
| @@ -349,11 +349,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
| 349 | 349 | ||
| 350 | next = rb_first(root); | 350 | next = rb_first(root); |
| 351 | 351 | ||
| 352 | machine = perf_session__find_host_machine(session); | ||
| 353 | if (!machine) { | ||
| 354 | pr_err("__print_result: couldn't find kernel information\n"); | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | while (next && n_lines--) { | 352 | while (next && n_lines--) { |
| 358 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, | 353 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, |
| 359 | node); | 354 | node); |
| @@ -614,8 +609,7 @@ static struct sort_dimension *avail_sorts[] = { | |||
| 614 | &pingpong_sort_dimension, | 609 | &pingpong_sort_dimension, |
| 615 | }; | 610 | }; |
| 616 | 611 | ||
| 617 | #define NUM_AVAIL_SORTS \ | 612 | #define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts)) |
| 618 | (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *)) | ||
| 619 | 613 | ||
| 620 | static int sort_dimension__add(const char *tok, struct list_head *list) | 614 | static int sort_dimension__add(const char *tok, struct list_head *list) |
| 621 | { | 615 | { |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index ca3f80ebc100..37a769d7f9fe 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -973,8 +973,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv) | |||
| 973 | 973 | ||
| 974 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | 974 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) |
| 975 | { | 975 | { |
| 976 | const char *file_name; | 976 | const char *file_name = NULL; |
| 977 | |||
| 978 | const struct option kvm_options[] = { | 977 | const struct option kvm_options[] = { |
| 979 | OPT_STRING('i', "input", &file_name, "file", | 978 | OPT_STRING('i', "input", &file_name, "file", |
| 980 | "Input file name"), | 979 | "Input file name"), |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 028de726b832..2ac690cad411 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -224,6 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
| 224 | 224 | ||
| 225 | static int perf_record__open(struct perf_record *rec) | 225 | static int perf_record__open(struct perf_record *rec) |
| 226 | { | 226 | { |
| 227 | char msg[512]; | ||
| 227 | struct perf_evsel *pos; | 228 | struct perf_evsel *pos; |
| 228 | struct perf_evlist *evlist = rec->evlist; | 229 | struct perf_evlist *evlist = rec->evlist; |
| 229 | struct perf_session *session = rec->session; | 230 | struct perf_session *session = rec->session; |
| @@ -233,114 +234,18 @@ static int perf_record__open(struct perf_record *rec) | |||
| 233 | perf_evlist__config(evlist, opts); | 234 | perf_evlist__config(evlist, opts); |
| 234 | 235 | ||
| 235 | list_for_each_entry(pos, &evlist->entries, node) { | 236 | list_for_each_entry(pos, &evlist->entries, node) { |
| 236 | struct perf_event_attr *attr = &pos->attr; | ||
| 237 | /* | ||
| 238 | * Check if parse_single_tracepoint_event has already asked for | ||
| 239 | * PERF_SAMPLE_TIME. | ||
| 240 | * | ||
| 241 | * XXX this is kludgy but short term fix for problems introduced by | ||
| 242 | * eac23d1c that broke 'perf script' by having different sample_types | ||
| 243 | * when using multiple tracepoint events when we use a perf binary | ||
| 244 | * that tries to use sample_id_all on an older kernel. | ||
| 245 | * | ||
| 246 | * We need to move counter creation to perf_session, support | ||
| 247 | * different sample_types, etc. | ||
| 248 | */ | ||
| 249 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; | ||
| 250 | |||
| 251 | fallback_missing_features: | ||
| 252 | if (opts->exclude_guest_missing) | ||
| 253 | attr->exclude_guest = attr->exclude_host = 0; | ||
| 254 | retry_sample_id: | ||
| 255 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | ||
| 256 | try_again: | 237 | try_again: |
| 257 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { | 238 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { |
| 258 | int err = errno; | 239 | if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { |
| 259 | |||
| 260 | if (err == EPERM || err == EACCES) { | ||
| 261 | ui__error_paranoid(); | ||
| 262 | rc = -err; | ||
| 263 | goto out; | ||
| 264 | } else if (err == ENODEV && opts->target.cpu_list) { | ||
| 265 | pr_err("No such device - did you specify" | ||
| 266 | " an out-of-range profile CPU?\n"); | ||
| 267 | rc = -err; | ||
| 268 | goto out; | ||
| 269 | } else if (err == EINVAL) { | ||
| 270 | if (!opts->exclude_guest_missing && | ||
| 271 | (attr->exclude_guest || attr->exclude_host)) { | ||
| 272 | pr_debug("Old kernel, cannot exclude " | ||
| 273 | "guest or host samples.\n"); | ||
| 274 | opts->exclude_guest_missing = true; | ||
| 275 | goto fallback_missing_features; | ||
| 276 | } else if (!opts->sample_id_all_missing) { | ||
| 277 | /* | ||
| 278 | * Old kernel, no attr->sample_id_type_all field | ||
| 279 | */ | ||
| 280 | opts->sample_id_all_missing = true; | ||
| 281 | if (!opts->sample_time && !opts->raw_samples && !time_needed) | ||
| 282 | perf_evsel__reset_sample_bit(pos, TIME); | ||
| 283 | |||
| 284 | goto retry_sample_id; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | /* | ||
| 289 | * If it's cycles then fall back to hrtimer | ||
| 290 | * based cpu-clock-tick sw counter, which | ||
| 291 | * is always available even if no PMU support. | ||
| 292 | * | ||
| 293 | * PPC returns ENXIO until 2.6.37 (behavior changed | ||
| 294 | * with commit b0a873e). | ||
| 295 | */ | ||
| 296 | if ((err == ENOENT || err == ENXIO) | ||
| 297 | && attr->type == PERF_TYPE_HARDWARE | ||
| 298 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { | ||
| 299 | |||
| 300 | if (verbose) | 240 | if (verbose) |
| 301 | ui__warning("The cycles event is not supported, " | 241 | ui__warning("%s\n", msg); |
| 302 | "trying to fall back to cpu-clock-ticks\n"); | ||
| 303 | attr->type = PERF_TYPE_SOFTWARE; | ||
| 304 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | ||
| 305 | if (pos->name) { | ||
| 306 | free(pos->name); | ||
| 307 | pos->name = NULL; | ||
| 308 | } | ||
| 309 | goto try_again; | 242 | goto try_again; |
| 310 | } | 243 | } |
| 311 | 244 | ||
| 312 | if (err == ENOENT) { | 245 | rc = -errno; |
| 313 | ui__error("The %s event is not supported.\n", | 246 | perf_evsel__open_strerror(pos, &opts->target, |
| 314 | perf_evsel__name(pos)); | 247 | errno, msg, sizeof(msg)); |
| 315 | rc = -err; | 248 | ui__error("%s\n", msg); |
| 316 | goto out; | ||
| 317 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
| 318 | ui__error("\'precise\' request may not be supported. " | ||
| 319 | "Try removing 'p' modifier\n"); | ||
| 320 | rc = -err; | ||
| 321 | goto out; | ||
| 322 | } | ||
| 323 | |||
| 324 | printf("\n"); | ||
| 325 | error("sys_perf_event_open() syscall returned with %d " | ||
| 326 | "(%s) for event %s. /bin/dmesg may provide " | ||
| 327 | "additional information.\n", | ||
| 328 | err, strerror(err), perf_evsel__name(pos)); | ||
| 329 | |||
| 330 | #if defined(__i386__) || defined(__x86_64__) | ||
| 331 | if (attr->type == PERF_TYPE_HARDWARE && | ||
| 332 | err == EOPNOTSUPP) { | ||
| 333 | pr_err("No hardware sampling interrupt available." | ||
| 334 | " No APIC? If so then you can boot the kernel" | ||
| 335 | " with the \"lapic\" boot parameter to" | ||
| 336 | " force-enable it.\n"); | ||
| 337 | rc = -err; | ||
| 338 | goto out; | ||
| 339 | } | ||
| 340 | #endif | ||
| 341 | |||
| 342 | pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | ||
| 343 | rc = -err; | ||
| 344 | goto out; | 249 | goto out; |
| 345 | } | 250 | } |
| 346 | } | 251 | } |
| @@ -423,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | |||
| 423 | { | 328 | { |
| 424 | int err; | 329 | int err; |
| 425 | struct perf_tool *tool = data; | 330 | struct perf_tool *tool = data; |
| 426 | |||
| 427 | if (machine__is_host(machine)) | ||
| 428 | return; | ||
| 429 | |||
| 430 | /* | 331 | /* |
| 431 | *As for guest kernel when processing subcommand record&report, | 332 | *As for guest kernel when processing subcommand record&report, |
| 432 | *we arrange module mmap prior to guest kernel mmap and trigger | 333 | *we arrange module mmap prior to guest kernel mmap and trigger |
| @@ -611,12 +512,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
| 611 | 512 | ||
| 612 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); | 513 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); |
| 613 | 514 | ||
| 614 | machine = perf_session__find_host_machine(session); | 515 | machine = &session->machines.host; |
| 615 | if (!machine) { | ||
| 616 | pr_err("Couldn't find native kernel information.\n"); | ||
| 617 | err = -1; | ||
| 618 | goto out_delete_session; | ||
| 619 | } | ||
| 620 | 516 | ||
| 621 | if (opts->pipe_output) { | 517 | if (opts->pipe_output) { |
| 622 | err = perf_event__synthesize_attrs(tool, session, | 518 | err = perf_event__synthesize_attrs(tool, session, |
| @@ -669,9 +565,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
| 669 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | 565 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
| 670 | "Check /proc/modules permission or run as root.\n"); | 566 | "Check /proc/modules permission or run as root.\n"); |
| 671 | 567 | ||
| 672 | if (perf_guest) | 568 | if (perf_guest) { |
| 673 | perf_session__process_machines(session, tool, | 569 | machines__process_guests(&session->machines, |
| 674 | perf_event__synthesize_guest_os); | 570 | perf_event__synthesize_guest_os, tool); |
| 571 | } | ||
| 675 | 572 | ||
| 676 | if (!opts->target.system_wide) | 573 | if (!opts->target.system_wide) |
| 677 | err = perf_event__synthesize_thread_map(tool, evsel_list->threads, | 574 | err = perf_event__synthesize_thread_map(tool, evsel_list->threads, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5134acf1c39a..47a864478543 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -372,7 +372,7 @@ static int __cmd_report(struct perf_report *rep) | |||
| 372 | if (ret) | 372 | if (ret) |
| 373 | goto out_delete; | 373 | goto out_delete; |
| 374 | 374 | ||
| 375 | kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; | 375 | kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
| 376 | kernel_kmap = map__kmap(kernel_map); | 376 | kernel_kmap = map__kmap(kernel_map); |
| 377 | if (kernel_map == NULL || | 377 | if (kernel_map == NULL || |
| 378 | (kernel_map->dso->hit && | 378 | (kernel_map->dso->hit && |
| @@ -595,8 +595,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 595 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, | 595 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, |
| 596 | "Use the stdio interface"), | 596 | "Use the stdio interface"), |
| 597 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 597 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
| 598 | "sort by key(s): pid, comm, dso, symbol, parent, dso_to," | 598 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," |
| 599 | " dso_from, symbol_to, symbol_from, mispredict"), | 599 | " dso_to, dso_from, symbol_to, symbol_from, mispredict"), |
| 600 | OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, | 600 | OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, |
| 601 | "Show sample percentage for different cpu modes"), | 601 | "Show sample percentage for different cpu modes"), |
| 602 | OPT_STRING('p', "parent", &parent_pattern, "regex", | 602 | OPT_STRING('p', "parent", &parent_pattern, "regex", |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index cc28b85dabd5..138229439a93 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, | |||
| 1475 | goto out_delete; | 1475 | goto out_delete; |
| 1476 | } | 1476 | } |
| 1477 | 1477 | ||
| 1478 | sched->nr_events = session->hists.stats.nr_events[0]; | 1478 | sched->nr_events = session->stats.nr_events[0]; |
| 1479 | sched->nr_lost_events = session->hists.stats.total_lost; | 1479 | sched->nr_lost_events = session->stats.total_lost; |
| 1480 | sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; | 1480 | sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; |
| 1481 | } | 1481 | } |
| 1482 | 1482 | ||
| 1483 | if (destroy) | 1483 | if (destroy) |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b363e7b292b2..92d4658f56fb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
| 692 | const char *arg, int unset __maybe_unused) | 692 | const char *arg, int unset __maybe_unused) |
| 693 | { | 693 | { |
| 694 | char *tok; | 694 | char *tok; |
| 695 | int i, imax = sizeof(all_output_options) / sizeof(struct output_option); | 695 | int i, imax = ARRAY_SIZE(all_output_options); |
| 696 | int j; | 696 | int j; |
| 697 | int rc = 0; | 697 | int rc = 0; |
| 698 | char *str = strdup(arg); | 698 | char *str = strdup(arg); |
| @@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix) | |||
| 909 | return NULL; | 909 | return NULL; |
| 910 | } | 910 | } |
| 911 | 911 | ||
| 912 | static char *ltrim(char *str) | ||
| 913 | { | ||
| 914 | int len = strlen(str); | ||
| 915 | |||
| 916 | while (len && isspace(*str)) { | ||
| 917 | len--; | ||
| 918 | str++; | ||
| 919 | } | ||
| 920 | |||
| 921 | return str; | ||
| 922 | } | ||
| 923 | |||
| 924 | static int read_script_info(struct script_desc *desc, const char *filename) | 912 | static int read_script_info(struct script_desc *desc, const char *filename) |
| 925 | { | 913 | { |
| 926 | char line[BUFSIZ], *p; | 914 | char line[BUFSIZ], *p; |
| @@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1487 | return -1; | 1475 | return -1; |
| 1488 | } | 1476 | } |
| 1489 | 1477 | ||
| 1490 | perf_session__fprintf_info(session, stdout, show_full_info); | 1478 | if (!script_name && !generate_script_lang) |
| 1479 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
| 1491 | 1480 | ||
| 1492 | if (!no_callchain) | 1481 | if (!no_callchain) |
| 1493 | symbol_conf.use_callchain = true; | 1482 | symbol_conf.use_callchain = true; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c12655af2b88..1c2ac148a7d5 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -132,8 +132,6 @@ static struct stats walltime_nsecs_stats; | |||
| 132 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 132 | static int create_perf_stat_counter(struct perf_evsel *evsel) |
| 133 | { | 133 | { |
| 134 | struct perf_event_attr *attr = &evsel->attr; | 134 | struct perf_event_attr *attr = &evsel->attr; |
| 135 | bool exclude_guest_missing = false; | ||
| 136 | int ret; | ||
| 137 | 135 | ||
| 138 | if (scale) | 136 | if (scale) |
| 139 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 137 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
| @@ -141,16 +139,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
| 141 | 139 | ||
| 142 | attr->inherit = !no_inherit; | 140 | attr->inherit = !no_inherit; |
| 143 | 141 | ||
| 144 | retry: | 142 | if (perf_target__has_cpu(&target)) |
| 145 | if (exclude_guest_missing) | 143 | return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); |
| 146 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | ||
| 147 | |||
| 148 | if (perf_target__has_cpu(&target)) { | ||
| 149 | ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); | ||
| 150 | if (ret) | ||
| 151 | goto check_ret; | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | 144 | ||
| 155 | if (!perf_target__has_task(&target) && | 145 | if (!perf_target__has_task(&target) && |
| 156 | perf_evsel__is_group_leader(evsel)) { | 146 | perf_evsel__is_group_leader(evsel)) { |
| @@ -158,21 +148,7 @@ retry: | |||
| 158 | attr->enable_on_exec = 1; | 148 | attr->enable_on_exec = 1; |
| 159 | } | 149 | } |
| 160 | 150 | ||
| 161 | ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); | 151 | return perf_evsel__open_per_thread(evsel, evsel_list->threads); |
| 162 | if (!ret) | ||
| 163 | return 0; | ||
| 164 | /* fall through */ | ||
| 165 | check_ret: | ||
| 166 | if (ret && errno == EINVAL) { | ||
| 167 | if (!exclude_guest_missing && | ||
| 168 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | ||
| 169 | pr_debug("Old kernel, cannot exclude " | ||
| 170 | "guest or host samples.\n"); | ||
| 171 | exclude_guest_missing = true; | ||
| 172 | goto retry; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | return ret; | ||
| 176 | } | 152 | } |
| 177 | 153 | ||
| 178 | /* | 154 | /* |
| @@ -271,6 +247,7 @@ static int read_counter(struct perf_evsel *counter) | |||
| 271 | 247 | ||
| 272 | static int __run_perf_stat(int argc __maybe_unused, const char **argv) | 248 | static int __run_perf_stat(int argc __maybe_unused, const char **argv) |
| 273 | { | 249 | { |
| 250 | char msg[512]; | ||
| 274 | unsigned long long t0, t1; | 251 | unsigned long long t0, t1; |
| 275 | struct perf_evsel *counter; | 252 | struct perf_evsel *counter; |
| 276 | int status = 0; | 253 | int status = 0; |
| @@ -348,20 +325,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
| 348 | continue; | 325 | continue; |
| 349 | } | 326 | } |
| 350 | 327 | ||
| 351 | if (errno == EPERM || errno == EACCES) { | 328 | perf_evsel__open_strerror(counter, &target, |
| 352 | error("You may not have permission to collect %sstats.\n" | 329 | errno, msg, sizeof(msg)); |
| 353 | "\t Consider tweaking" | 330 | ui__error("%s\n", msg); |
| 354 | " /proc/sys/kernel/perf_event_paranoid or running as root.", | 331 | |
| 355 | target.system_wide ? "system-wide " : ""); | ||
| 356 | } else { | ||
| 357 | error("open_counter returned with %d (%s). " | ||
| 358 | "/bin/dmesg may provide additional information.\n", | ||
| 359 | errno, strerror(errno)); | ||
| 360 | } | ||
| 361 | if (child_pid != -1) | 332 | if (child_pid != -1) |
| 362 | kill(child_pid, SIGTERM); | 333 | kill(child_pid, SIGTERM); |
| 363 | 334 | ||
| 364 | pr_err("Not all events could be opened.\n"); | ||
| 365 | return -1; | 335 | return -1; |
| 366 | } | 336 | } |
| 367 | counter->supported = true; | 337 | counter->supported = true; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b7d2ea62dbc6..7978c8117b7f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -68,28 +68,6 @@ | |||
| 68 | #include <linux/unistd.h> | 68 | #include <linux/unistd.h> |
| 69 | #include <linux/types.h> | 69 | #include <linux/types.h> |
| 70 | 70 | ||
| 71 | void get_term_dimensions(struct winsize *ws) | ||
| 72 | { | ||
| 73 | char *s = getenv("LINES"); | ||
| 74 | |||
| 75 | if (s != NULL) { | ||
| 76 | ws->ws_row = atoi(s); | ||
| 77 | s = getenv("COLUMNS"); | ||
| 78 | if (s != NULL) { | ||
| 79 | ws->ws_col = atoi(s); | ||
| 80 | if (ws->ws_row && ws->ws_col) | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | #ifdef TIOCGWINSZ | ||
| 85 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
| 86 | ws->ws_row && ws->ws_col) | ||
| 87 | return; | ||
| 88 | #endif | ||
| 89 | ws->ws_row = 25; | ||
| 90 | ws->ws_col = 80; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void perf_top__update_print_entries(struct perf_top *top) | 71 | static void perf_top__update_print_entries(struct perf_top *top) |
| 94 | { | 72 | { |
| 95 | if (top->print_entries > 9) | 73 | if (top->print_entries > 9) |
| @@ -716,7 +694,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
| 716 | static struct intlist *seen; | 694 | static struct intlist *seen; |
| 717 | 695 | ||
| 718 | if (!seen) | 696 | if (!seen) |
| 719 | seen = intlist__new(); | 697 | seen = intlist__new(NULL); |
| 720 | 698 | ||
| 721 | if (!intlist__has_entry(seen, event->ip.pid)) { | 699 | if (!intlist__has_entry(seen, event->ip.pid)) { |
| 722 | pr_err("Can't find guest [%d]'s kernel information\n", | 700 | pr_err("Can't find guest [%d]'s kernel information\n", |
| @@ -728,7 +706,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
| 728 | 706 | ||
| 729 | if (!machine) { | 707 | if (!machine) { |
| 730 | pr_err("%u unprocessable samples recorded.\n", | 708 | pr_err("%u unprocessable samples recorded.\n", |
| 731 | top->session->hists.stats.nr_unprocessable_samples++); | 709 | top->session->stats.nr_unprocessable_samples++); |
| 732 | return; | 710 | return; |
| 733 | } | 711 | } |
| 734 | 712 | ||
| @@ -847,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 847 | ++top->us_samples; | 825 | ++top->us_samples; |
| 848 | if (top->hide_user_symbols) | 826 | if (top->hide_user_symbols) |
| 849 | continue; | 827 | continue; |
| 850 | machine = perf_session__find_host_machine(session); | 828 | machine = &session->machines.host; |
| 851 | break; | 829 | break; |
| 852 | case PERF_RECORD_MISC_KERNEL: | 830 | case PERF_RECORD_MISC_KERNEL: |
| 853 | ++top->kernel_samples; | 831 | ++top->kernel_samples; |
| 854 | if (top->hide_kernel_symbols) | 832 | if (top->hide_kernel_symbols) |
| 855 | continue; | 833 | continue; |
| 856 | machine = perf_session__find_host_machine(session); | 834 | machine = &session->machines.host; |
| 857 | break; | 835 | break; |
| 858 | case PERF_RECORD_MISC_GUEST_KERNEL: | 836 | case PERF_RECORD_MISC_GUEST_KERNEL: |
| 859 | ++top->guest_kernel_samples; | 837 | ++top->guest_kernel_samples; |
| @@ -878,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 878 | hists__inc_nr_events(&evsel->hists, event->header.type); | 856 | hists__inc_nr_events(&evsel->hists, event->header.type); |
| 879 | machine__process_event(machine, event); | 857 | machine__process_event(machine, event); |
| 880 | } else | 858 | } else |
| 881 | ++session->hists.stats.nr_unknown_events; | 859 | ++session->stats.nr_unknown_events; |
| 882 | } | 860 | } |
| 883 | } | 861 | } |
| 884 | 862 | ||
| @@ -892,6 +870,7 @@ static void perf_top__mmap_read(struct perf_top *top) | |||
| 892 | 870 | ||
| 893 | static void perf_top__start_counters(struct perf_top *top) | 871 | static void perf_top__start_counters(struct perf_top *top) |
| 894 | { | 872 | { |
| 873 | char msg[512]; | ||
| 895 | struct perf_evsel *counter; | 874 | struct perf_evsel *counter; |
| 896 | struct perf_evlist *evlist = top->evlist; | 875 | struct perf_evlist *evlist = top->evlist; |
| 897 | struct perf_record_opts *opts = &top->record_opts; | 876 | struct perf_record_opts *opts = &top->record_opts; |
| @@ -899,77 +878,18 @@ static void perf_top__start_counters(struct perf_top *top) | |||
| 899 | perf_evlist__config(evlist, opts); | 878 | perf_evlist__config(evlist, opts); |
| 900 | 879 | ||
| 901 | list_for_each_entry(counter, &evlist->entries, node) { | 880 | list_for_each_entry(counter, &evlist->entries, node) { |
| 902 | struct perf_event_attr *attr = &counter->attr; | ||
| 903 | |||
| 904 | fallback_missing_features: | ||
| 905 | if (top->exclude_guest_missing) | ||
| 906 | attr->exclude_guest = attr->exclude_host = 0; | ||
| 907 | retry_sample_id: | ||
| 908 | attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; | ||
| 909 | try_again: | 881 | try_again: |
| 910 | if (perf_evsel__open(counter, top->evlist->cpus, | 882 | if (perf_evsel__open(counter, top->evlist->cpus, |
| 911 | top->evlist->threads) < 0) { | 883 | top->evlist->threads) < 0) { |
| 912 | int err = errno; | 884 | if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { |
| 913 | |||
| 914 | if (err == EPERM || err == EACCES) { | ||
| 915 | ui__error_paranoid(); | ||
| 916 | goto out_err; | ||
| 917 | } else if (err == EINVAL) { | ||
| 918 | if (!top->exclude_guest_missing && | ||
| 919 | (attr->exclude_guest || attr->exclude_host)) { | ||
| 920 | pr_debug("Old kernel, cannot exclude " | ||
| 921 | "guest or host samples.\n"); | ||
| 922 | top->exclude_guest_missing = true; | ||
| 923 | goto fallback_missing_features; | ||
| 924 | } else if (!top->sample_id_all_missing) { | ||
| 925 | /* | ||
| 926 | * Old kernel, no attr->sample_id_type_all field | ||
| 927 | */ | ||
| 928 | top->sample_id_all_missing = true; | ||
| 929 | goto retry_sample_id; | ||
| 930 | } | ||
| 931 | } | ||
| 932 | /* | ||
| 933 | * If it's cycles then fall back to hrtimer | ||
| 934 | * based cpu-clock-tick sw counter, which | ||
| 935 | * is always available even if no PMU support: | ||
| 936 | */ | ||
| 937 | if ((err == ENOENT || err == ENXIO) && | ||
| 938 | (attr->type == PERF_TYPE_HARDWARE) && | ||
| 939 | (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { | ||
| 940 | |||
| 941 | if (verbose) | 885 | if (verbose) |
| 942 | ui__warning("Cycles event not supported,\n" | 886 | ui__warning("%s\n", msg); |
| 943 | "trying to fall back to cpu-clock-ticks\n"); | ||
| 944 | |||
| 945 | attr->type = PERF_TYPE_SOFTWARE; | ||
| 946 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | ||
| 947 | if (counter->name) { | ||
| 948 | free(counter->name); | ||
| 949 | counter->name = NULL; | ||
| 950 | } | ||
| 951 | goto try_again; | 887 | goto try_again; |
| 952 | } | 888 | } |
| 953 | 889 | ||
| 954 | if (err == ENOENT) { | 890 | perf_evsel__open_strerror(counter, &opts->target, |
| 955 | ui__error("The %s event is not supported.\n", | 891 | errno, msg, sizeof(msg)); |
| 956 | perf_evsel__name(counter)); | 892 | ui__error("%s\n", msg); |
| 957 | goto out_err; | ||
| 958 | } else if (err == EMFILE) { | ||
| 959 | ui__error("Too many events are opened.\n" | ||
| 960 | "Try again after reducing the number of events\n"); | ||
| 961 | goto out_err; | ||
| 962 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
| 963 | ui__error("\'precise\' request may not be supported. " | ||
| 964 | "Try removing 'p' modifier\n"); | ||
| 965 | goto out_err; | ||
| 966 | } | ||
| 967 | |||
| 968 | ui__error("The sys_perf_event_open() syscall " | ||
| 969 | "returned with %d (%s). /bin/dmesg " | ||
| 970 | "may provide additional information.\n" | ||
| 971 | "No CONFIG_PERF_EVENTS=y kernel support " | ||
| 972 | "configured?\n", err, strerror(err)); | ||
| 973 | goto out_err; | 893 | goto out_err; |
| 974 | } | 894 | } |
| 975 | } | 895 | } |
| @@ -1024,10 +944,10 @@ static int __cmd_top(struct perf_top *top) | |||
| 1024 | if (perf_target__has_task(&opts->target)) | 944 | if (perf_target__has_task(&opts->target)) |
| 1025 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 945 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
| 1026 | perf_event__process, | 946 | perf_event__process, |
| 1027 | &top->session->host_machine); | 947 | &top->session->machines.host); |
| 1028 | else | 948 | else |
| 1029 | perf_event__synthesize_threads(&top->tool, perf_event__process, | 949 | perf_event__synthesize_threads(&top->tool, perf_event__process, |
| 1030 | &top->session->host_machine); | 950 | &top->session->machines.host); |
| 1031 | perf_top__start_counters(top); | 951 | perf_top__start_counters(top); |
| 1032 | top->session->evlist = top->evlist; | 952 | top->session->evlist = top->evlist; |
| 1033 | perf_session__set_id_hdr_size(top->session); | 953 | perf_session__set_id_hdr_size(top->session); |
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index e5413125e6bb..8ef3bd30a549 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
| @@ -13,7 +13,7 @@ newline := $(newline) | |||
| 13 | # what should replace a newline when escaping | 13 | # what should replace a newline when escaping |
| 14 | # newlines; the default is a bizarre string. | 14 | # newlines; the default is a bizarre string. |
| 15 | # | 15 | # |
| 16 | nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) | 16 | nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n) |
| 17 | 17 | ||
| 18 | # escape-nl | 18 | # escape-nl |
| 19 | # | 19 | # |
| @@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1)) | |||
| 173 | # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) | 173 | # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) |
| 174 | # | 174 | # |
| 175 | define get-executable-or-default | 175 | define get-executable-or-default |
| 176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) | 176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1))) |
| 177 | endef | 177 | endef |
| 178 | _ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) | 178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) |
| 179 | _gea_warn = $(warning The path '$(1)' is not executable.) | 179 | _gea_warn = $(warning The path '$(1)' is not executable.) |
| 180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) | 180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) |
| 181 | 181 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 0f661fbce6a8..095b88207cd3 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -328,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
| 328 | if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) | 328 | if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) |
| 329 | return 0; | 329 | return 0; |
| 330 | 330 | ||
| 331 | status = 1; | ||
| 331 | /* Check for ENOSPC and EIO errors.. */ | 332 | /* Check for ENOSPC and EIO errors.. */ |
| 332 | if (fflush(stdout)) | 333 | if (fflush(stdout)) { |
| 333 | die("write failure on standard output: %s", strerror(errno)); | 334 | fprintf(stderr, "write failure on standard output: %s", strerror(errno)); |
| 334 | if (ferror(stdout)) | 335 | goto out; |
| 335 | die("unknown write failure on standard output"); | 336 | } |
| 336 | if (fclose(stdout)) | 337 | if (ferror(stdout)) { |
| 337 | die("close failed on standard output: %s", strerror(errno)); | 338 | fprintf(stderr, "unknown write failure on standard output"); |
| 338 | return 0; | 339 | goto out; |
| 340 | } | ||
| 341 | if (fclose(stdout)) { | ||
| 342 | fprintf(stderr, "close failed on standard output: %s", strerror(errno)); | ||
| 343 | goto out; | ||
| 344 | } | ||
| 345 | status = 0; | ||
| 346 | out: | ||
| 347 | return status; | ||
| 339 | } | 348 | } |
| 340 | 349 | ||
| 341 | static void handle_internal_command(int argc, const char **argv) | 350 | static void handle_internal_command(int argc, const char **argv) |
| @@ -467,7 +476,8 @@ int main(int argc, const char **argv) | |||
| 467 | cmd += 5; | 476 | cmd += 5; |
| 468 | argv[0] = cmd; | 477 | argv[0] = cmd; |
| 469 | handle_internal_command(argc, argv); | 478 | handle_internal_command(argc, argv); |
| 470 | die("cannot handle %s internally", cmd); | 479 | fprintf(stderr, "cannot handle %s internally", cmd); |
| 480 | goto out; | ||
| 471 | } | 481 | } |
| 472 | 482 | ||
| 473 | /* Look for flags.. */ | 483 | /* Look for flags.. */ |
| @@ -485,7 +495,7 @@ int main(int argc, const char **argv) | |||
| 485 | printf("\n usage: %s\n\n", perf_usage_string); | 495 | printf("\n usage: %s\n\n", perf_usage_string); |
| 486 | list_common_cmds_help(); | 496 | list_common_cmds_help(); |
| 487 | printf("\n %s\n\n", perf_more_info_string); | 497 | printf("\n %s\n\n", perf_more_info_string); |
| 488 | exit(1); | 498 | goto out; |
| 489 | } | 499 | } |
| 490 | cmd = argv[0]; | 500 | cmd = argv[0]; |
| 491 | 501 | ||
| @@ -517,7 +527,7 @@ int main(int argc, const char **argv) | |||
| 517 | fprintf(stderr, "Expansion of alias '%s' failed; " | 527 | fprintf(stderr, "Expansion of alias '%s' failed; " |
| 518 | "'%s' is not a perf-command\n", | 528 | "'%s' is not a perf-command\n", |
| 519 | cmd, argv[0]); | 529 | cmd, argv[0]); |
| 520 | exit(1); | 530 | goto out; |
| 521 | } | 531 | } |
| 522 | if (!done_help) { | 532 | if (!done_help) { |
| 523 | cmd = argv[0] = help_unknown_cmd(cmd); | 533 | cmd = argv[0] = help_unknown_cmd(cmd); |
| @@ -528,6 +538,6 @@ int main(int argc, const char **argv) | |||
| 528 | 538 | ||
| 529 | fprintf(stderr, "Failed to run command '%s': %s\n", | 539 | fprintf(stderr, "Failed to run command '%s': %s\n", |
| 530 | cmd, strerror(errno)); | 540 | cmd, strerror(errno)); |
| 531 | 541 | out: | |
| 532 | return 1; | 542 | return 1; |
| 533 | } | 543 | } |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2c340e7da458..8f3bf388e414 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -1,10 +1,6 @@ | |||
| 1 | #ifndef _PERF_PERF_H | 1 | #ifndef _PERF_PERF_H |
| 2 | #define _PERF_PERF_H | 2 | #define _PERF_PERF_H |
| 3 | 3 | ||
| 4 | struct winsize; | ||
| 5 | |||
| 6 | void get_term_dimensions(struct winsize *ws); | ||
| 7 | |||
| 8 | #include <asm/unistd.h> | 4 | #include <asm/unistd.h> |
| 9 | 5 | ||
| 10 | #if defined(__i386__) | 6 | #if defined(__i386__) |
| @@ -237,8 +233,6 @@ struct perf_record_opts { | |||
| 237 | bool raw_samples; | 233 | bool raw_samples; |
| 238 | bool sample_address; | 234 | bool sample_address; |
| 239 | bool sample_time; | 235 | bool sample_time; |
| 240 | bool sample_id_all_missing; | ||
| 241 | bool exclude_guest_missing; | ||
| 242 | bool period; | 236 | bool period; |
| 243 | unsigned int freq; | 237 | unsigned int freq; |
| 244 | unsigned int mmap_pages; | 238 | unsigned int mmap_pages; |
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record deleted file mode 100644 index 8edda9078d5d..000000000000 --- a/tools/perf/scripts/perl/bin/workqueue-stats-record +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ | ||
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report deleted file mode 100644 index 6d91411d248c..000000000000 --- a/tools/perf/scripts/perl/bin/workqueue-stats-report +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # description: workqueue stats (ins/exe/create/destroy) | ||
| 3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl | ||
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl deleted file mode 100644 index a8eaff5119e0..000000000000 --- a/tools/perf/scripts/perl/workqueue-stats.pl +++ /dev/null | |||
| @@ -1,129 +0,0 @@ | |||
| 1 | #!/usr/bin/perl -w | ||
| 2 | # (c) 2009, Tom Zanussi <tzanussi@gmail.com> | ||
| 3 | # Licensed under the terms of the GNU GPL License version 2 | ||
| 4 | |||
| 5 | # Displays workqueue stats | ||
| 6 | # | ||
| 7 | # Usage: | ||
| 8 | # | ||
| 9 | # perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e | ||
| 10 | # workqueue:workqueue_destruction -e workqueue:workqueue_execution | ||
| 11 | # -e workqueue:workqueue_insertion | ||
| 12 | # | ||
| 13 | # perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl | ||
| 14 | |||
| 15 | use 5.010000; | ||
| 16 | use strict; | ||
| 17 | use warnings; | ||
| 18 | |||
| 19 | use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | ||
| 20 | use lib "./Perf-Trace-Util/lib"; | ||
| 21 | use Perf::Trace::Core; | ||
| 22 | use Perf::Trace::Util; | ||
| 23 | |||
| 24 | my @cpus; | ||
| 25 | |||
| 26 | sub workqueue::workqueue_destruction | ||
| 27 | { | ||
| 28 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
| 29 | $common_pid, $common_comm, | ||
| 30 | $thread_comm, $thread_pid) = @_; | ||
| 31 | |||
| 32 | $cpus[$common_cpu]{$thread_pid}{destroyed}++; | ||
| 33 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
| 34 | } | ||
| 35 | |||
| 36 | sub workqueue::workqueue_creation | ||
| 37 | { | ||
| 38 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
| 39 | $common_pid, $common_comm, | ||
| 40 | $thread_comm, $thread_pid, $cpu) = @_; | ||
| 41 | |||
| 42 | $cpus[$common_cpu]{$thread_pid}{created}++; | ||
| 43 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
| 44 | } | ||
| 45 | |||
| 46 | sub workqueue::workqueue_execution | ||
| 47 | { | ||
| 48 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
| 49 | $common_pid, $common_comm, | ||
| 50 | $thread_comm, $thread_pid, $func) = @_; | ||
| 51 | |||
| 52 | $cpus[$common_cpu]{$thread_pid}{executed}++; | ||
| 53 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
| 54 | } | ||
| 55 | |||
| 56 | sub workqueue::workqueue_insertion | ||
| 57 | { | ||
| 58 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
| 59 | $common_pid, $common_comm, | ||
| 60 | $thread_comm, $thread_pid, $func) = @_; | ||
| 61 | |||
| 62 | $cpus[$common_cpu]{$thread_pid}{inserted}++; | ||
| 63 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
| 64 | } | ||
| 65 | |||
| 66 | sub trace_end | ||
| 67 | { | ||
| 68 | print "workqueue work stats:\n\n"; | ||
| 69 | my $cpu = 0; | ||
| 70 | printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name"); | ||
| 71 | printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----"); | ||
| 72 | foreach my $pidhash (@cpus) { | ||
| 73 | while ((my $pid, my $wqhash) = each %$pidhash) { | ||
| 74 | my $ins = $$wqhash{'inserted'} || 0; | ||
| 75 | my $exe = $$wqhash{'executed'} || 0; | ||
| 76 | my $comm = $$wqhash{'comm'} || ""; | ||
| 77 | if ($ins || $exe) { | ||
| 78 | printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | $cpu++; | ||
| 82 | } | ||
| 83 | |||
| 84 | $cpu = 0; | ||
| 85 | print "\nworkqueue lifecycle stats:\n\n"; | ||
| 86 | printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name"); | ||
| 87 | printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----"); | ||
| 88 | foreach my $pidhash (@cpus) { | ||
| 89 | while ((my $pid, my $wqhash) = each %$pidhash) { | ||
| 90 | my $created = $$wqhash{'created'} || 0; | ||
| 91 | my $destroyed = $$wqhash{'destroyed'} || 0; | ||
| 92 | my $comm = $$wqhash{'comm'} || ""; | ||
| 93 | if ($created || $destroyed) { | ||
| 94 | printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed, | ||
| 95 | $comm); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | $cpu++; | ||
| 99 | } | ||
| 100 | |||
| 101 | print_unhandled(); | ||
| 102 | } | ||
| 103 | |||
| 104 | my %unhandled; | ||
| 105 | |||
| 106 | sub print_unhandled | ||
| 107 | { | ||
| 108 | if ((scalar keys %unhandled) == 0) { | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | |||
| 112 | print "\nunhandled events:\n\n"; | ||
| 113 | |||
| 114 | printf("%-40s %10s\n", "event", "count"); | ||
| 115 | printf("%-40s %10s\n", "----------------------------------------", | ||
| 116 | "-----------"); | ||
| 117 | |||
| 118 | foreach my $event_name (keys %unhandled) { | ||
| 119 | printf("%-40s %10d\n", $event_name, $unhandled{$event_name}); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | sub trace_unhandled | ||
| 124 | { | ||
| 125 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
| 126 | $common_pid, $common_comm) = @_; | ||
| 127 | |||
| 128 | $unhandled{$event_name}++; | ||
| 129 | } | ||
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 25638a986257..f61dd3fb546b 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
| @@ -33,8 +33,6 @@ | |||
| 33 | 33 | ||
| 34 | extern int verbose; | 34 | extern int verbose; |
| 35 | 35 | ||
| 36 | bool test_attr__enabled; | ||
| 37 | |||
| 38 | static char *dir; | 36 | static char *dir; |
| 39 | 37 | ||
| 40 | void test_attr__init(void) | 38 | void test_attr__init(void) |
| @@ -146,7 +144,7 @@ static int run_dir(const char *d, const char *perf) | |||
| 146 | { | 144 | { |
| 147 | char cmd[3*PATH_MAX]; | 145 | char cmd[3*PATH_MAX]; |
| 148 | 146 | ||
| 149 | snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s", | 147 | snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s", |
| 150 | d, d, perf, verbose ? "-v" : ""); | 148 | d, d, perf, verbose ? "-v" : ""); |
| 151 | 149 | ||
| 152 | return system(cmd); | 150 | return system(cmd); |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index e702b82dcb86..2f629ca485bc 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
| @@ -68,7 +68,7 @@ class Event(dict): | |||
| 68 | self[key] = val | 68 | self[key] = val |
| 69 | 69 | ||
| 70 | def __init__(self, name, data, base): | 70 | def __init__(self, name, data, base): |
| 71 | log.info(" Event %s" % name); | 71 | log.debug(" Event %s" % name); |
| 72 | self.name = name; | 72 | self.name = name; |
| 73 | self.group = '' | 73 | self.group = '' |
| 74 | self.add(base) | 74 | self.add(base) |
| @@ -97,6 +97,14 @@ class Event(dict): | |||
| 97 | return False | 97 | return False |
| 98 | return True | 98 | return True |
| 99 | 99 | ||
| 100 | def diff(self, other): | ||
| 101 | for t in Event.terms: | ||
| 102 | if not self.has_key(t) or not other.has_key(t): | ||
| 103 | continue | ||
| 104 | if not self.compare_data(self[t], other[t]): | ||
| 105 | log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) | ||
| 106 | |||
| 107 | |||
| 100 | # Test file description needs to have following sections: | 108 | # Test file description needs to have following sections: |
| 101 | # [config] | 109 | # [config] |
| 102 | # - just single instance in file | 110 | # - just single instance in file |
| @@ -113,7 +121,7 @@ class Test(object): | |||
| 113 | parser = ConfigParser.SafeConfigParser() | 121 | parser = ConfigParser.SafeConfigParser() |
| 114 | parser.read(path) | 122 | parser.read(path) |
| 115 | 123 | ||
| 116 | log.warning("running '%s'" % path) | 124 | log.debug("running '%s'" % path) |
| 117 | 125 | ||
| 118 | self.path = path | 126 | self.path = path |
| 119 | self.test_dir = options.test_dir | 127 | self.test_dir = options.test_dir |
| @@ -128,7 +136,7 @@ class Test(object): | |||
| 128 | 136 | ||
| 129 | self.expect = {} | 137 | self.expect = {} |
| 130 | self.result = {} | 138 | self.result = {} |
| 131 | log.info(" loading expected events"); | 139 | log.debug(" loading expected events"); |
| 132 | self.load_events(path, self.expect) | 140 | self.load_events(path, self.expect) |
| 133 | 141 | ||
| 134 | def is_event(self, name): | 142 | def is_event(self, name): |
| @@ -164,7 +172,7 @@ class Test(object): | |||
| 164 | self.perf, self.command, tempdir, self.args) | 172 | self.perf, self.command, tempdir, self.args) |
| 165 | ret = os.WEXITSTATUS(os.system(cmd)) | 173 | ret = os.WEXITSTATUS(os.system(cmd)) |
| 166 | 174 | ||
| 167 | log.info(" running '%s' ret %d " % (cmd, ret)) | 175 | log.warning(" running '%s' ret %d " % (cmd, ret)) |
| 168 | 176 | ||
| 169 | if ret != int(self.ret): | 177 | if ret != int(self.ret): |
| 170 | raise Unsup(self) | 178 | raise Unsup(self) |
| @@ -172,7 +180,7 @@ class Test(object): | |||
| 172 | def compare(self, expect, result): | 180 | def compare(self, expect, result): |
| 173 | match = {} | 181 | match = {} |
| 174 | 182 | ||
| 175 | log.info(" compare"); | 183 | log.debug(" compare"); |
| 176 | 184 | ||
| 177 | # For each expected event find all matching | 185 | # For each expected event find all matching |
| 178 | # events in result. Fail if there's not any. | 186 | # events in result. Fail if there's not any. |
| @@ -187,10 +195,11 @@ class Test(object): | |||
| 187 | else: | 195 | else: |
| 188 | log.debug(" ->FAIL"); | 196 | log.debug(" ->FAIL"); |
| 189 | 197 | ||
| 190 | log.info(" match: [%s] matches %s" % (exp_name, str(exp_list))) | 198 | log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) |
| 191 | 199 | ||
| 192 | # we did not any matching event - fail | 200 | # we did not any matching event - fail |
| 193 | if (not exp_list): | 201 | if (not exp_list): |
| 202 | exp_event.diff(res_event) | ||
| 194 | raise Fail(self, 'match failure'); | 203 | raise Fail(self, 'match failure'); |
| 195 | 204 | ||
| 196 | match[exp_name] = exp_list | 205 | match[exp_name] = exp_list |
| @@ -208,10 +217,10 @@ class Test(object): | |||
| 208 | if res_group not in match[group]: | 217 | if res_group not in match[group]: |
| 209 | raise Fail(self, 'group failure') | 218 | raise Fail(self, 'group failure') |
| 210 | 219 | ||
| 211 | log.info(" group: [%s] matches group leader %s" % | 220 | log.debug(" group: [%s] matches group leader %s" % |
| 212 | (exp_name, str(match[group]))) | 221 | (exp_name, str(match[group]))) |
| 213 | 222 | ||
| 214 | log.info(" matched") | 223 | log.debug(" matched") |
| 215 | 224 | ||
| 216 | def resolve_groups(self, events): | 225 | def resolve_groups(self, events): |
| 217 | for name, event in events.items(): | 226 | for name, event in events.items(): |
| @@ -233,7 +242,7 @@ class Test(object): | |||
| 233 | self.run_cmd(tempdir); | 242 | self.run_cmd(tempdir); |
| 234 | 243 | ||
| 235 | # load events expectation for the test | 244 | # load events expectation for the test |
| 236 | log.info(" loading result events"); | 245 | log.debug(" loading result events"); |
| 237 | for f in glob.glob(tempdir + '/event*'): | 246 | for f in glob.glob(tempdir + '/event*'): |
| 238 | self.load_events(f, self.result); | 247 | self.load_events(f, self.result); |
| 239 | 248 | ||
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 index 4d688a13fd2f..c5548d054aff 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/attr/test-record-group1 | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [config] | 1 | [config] |
| 2 | command = record | 2 | command = record |
| 3 | args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 | 3 | args = -e '{cycles,instructions}' kill >/dev/null 2>&1 |
| 4 | 4 | ||
| 5 | [event-1:base-record] | 5 | [event-1:base-record] |
| 6 | fd=1 | 6 | fd=1 |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 186f67535494..acb98e0e39f2 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | * Builtin regression testing command: ever growing number of sanity tests | 4 | * Builtin regression testing command: ever growing number of sanity tests |
| 5 | */ | 5 | */ |
| 6 | #include "builtin.h" | 6 | #include "builtin.h" |
| 7 | #include "intlist.h" | ||
| 7 | #include "tests.h" | 8 | #include "tests.h" |
| 8 | #include "debug.h" | 9 | #include "debug.h" |
| 9 | #include "color.h" | 10 | #include "color.h" |
| @@ -69,6 +70,14 @@ static struct test { | |||
| 69 | .func = test__attr, | 70 | .func = test__attr, |
| 70 | }, | 71 | }, |
| 71 | { | 72 | { |
| 73 | .desc = "Test matching and linking mutliple hists", | ||
| 74 | .func = test__hists_link, | ||
| 75 | }, | ||
| 76 | { | ||
| 77 | .desc = "Try 'use perf' in python, checking link problems", | ||
| 78 | .func = test__python_use, | ||
| 79 | }, | ||
| 80 | { | ||
| 72 | .func = NULL, | 81 | .func = NULL, |
| 73 | }, | 82 | }, |
| 74 | }; | 83 | }; |
| @@ -97,7 +106,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) | |||
| 97 | return false; | 106 | return false; |
| 98 | } | 107 | } |
| 99 | 108 | ||
| 100 | static int __cmd_test(int argc, const char *argv[]) | 109 | static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) |
| 101 | { | 110 | { |
| 102 | int i = 0; | 111 | int i = 0; |
| 103 | int width = 0; | 112 | int width = 0; |
| @@ -118,13 +127,28 @@ static int __cmd_test(int argc, const char *argv[]) | |||
| 118 | continue; | 127 | continue; |
| 119 | 128 | ||
| 120 | pr_info("%2d: %-*s:", i, width, tests[curr].desc); | 129 | pr_info("%2d: %-*s:", i, width, tests[curr].desc); |
| 130 | |||
| 131 | if (intlist__find(skiplist, i)) { | ||
| 132 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); | ||
| 133 | continue; | ||
| 134 | } | ||
| 135 | |||
| 121 | pr_debug("\n--- start ---\n"); | 136 | pr_debug("\n--- start ---\n"); |
| 122 | err = tests[curr].func(); | 137 | err = tests[curr].func(); |
| 123 | pr_debug("---- end ----\n%s:", tests[curr].desc); | 138 | pr_debug("---- end ----\n%s:", tests[curr].desc); |
| 124 | if (err) | 139 | |
| 125 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | 140 | switch (err) { |
| 126 | else | 141 | case TEST_OK: |
| 127 | pr_info(" Ok\n"); | 142 | pr_info(" Ok\n"); |
| 143 | break; | ||
| 144 | case TEST_SKIP: | ||
| 145 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); | ||
| 146 | break; | ||
| 147 | case TEST_FAIL: | ||
| 148 | default: | ||
| 149 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | ||
| 150 | break; | ||
| 151 | } | ||
| 128 | } | 152 | } |
| 129 | 153 | ||
| 130 | return 0; | 154 | return 0; |
| @@ -152,11 +176,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 152 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", | 176 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", |
| 153 | NULL, | 177 | NULL, |
| 154 | }; | 178 | }; |
| 179 | const char *skip = NULL; | ||
| 155 | const struct option test_options[] = { | 180 | const struct option test_options[] = { |
| 181 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), | ||
| 156 | OPT_INCR('v', "verbose", &verbose, | 182 | OPT_INCR('v', "verbose", &verbose, |
| 157 | "be more verbose (show symbol address, etc)"), | 183 | "be more verbose (show symbol address, etc)"), |
| 158 | OPT_END() | 184 | OPT_END() |
| 159 | }; | 185 | }; |
| 186 | struct intlist *skiplist = NULL; | ||
| 160 | 187 | ||
| 161 | argc = parse_options(argc, argv, test_options, test_usage, 0); | 188 | argc = parse_options(argc, argv, test_options, test_usage, 0); |
| 162 | if (argc >= 1 && !strcmp(argv[0], "list")) | 189 | if (argc >= 1 && !strcmp(argv[0], "list")) |
| @@ -169,5 +196,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 169 | if (symbol__init() < 0) | 196 | if (symbol__init() < 0) |
| 170 | return -1; | 197 | return -1; |
| 171 | 198 | ||
| 172 | return __cmd_test(argc, argv); | 199 | if (skip != NULL) |
| 200 | skiplist = intlist__new(skip); | ||
| 201 | |||
| 202 | return __cmd_test(argc, argv, skiplist); | ||
| 173 | } | 203 | } |
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index e61fc828a158..0fd99a9adb91 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c | |||
| @@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) | |||
| 22 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | 22 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
| 23 | __perf_evsel__hw_cache_type_op_res_name(type, op, i, | 23 | __perf_evsel__hw_cache_type_op_res_name(type, op, i, |
| 24 | name, sizeof(name)); | 24 | name, sizeof(name)); |
| 25 | err = parse_events(evlist, name, 0); | 25 | err = parse_events(evlist, name); |
| 26 | if (err) | 26 | if (err) |
| 27 | ret = err; | 27 | ret = err; |
| 28 | } | 28 | } |
| @@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) | |||
| 70 | return -ENOMEM; | 70 | return -ENOMEM; |
| 71 | 71 | ||
| 72 | for (i = 0; i < nr_names; ++i) { | 72 | for (i = 0; i < nr_names; ++i) { |
| 73 | err = parse_events(evlist, names[i], 0); | 73 | err = parse_events(evlist, names[i]); |
| 74 | if (err) { | 74 | if (err) { |
| 75 | pr_debug("failed to parse event '%s', err %d\n", | 75 | pr_debug("failed to parse event '%s', err %d\n", |
| 76 | names[i], err); | 76 | names[i], err); |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c new file mode 100644 index 000000000000..0afd9223bde7 --- /dev/null +++ b/tools/perf/tests/hists_link.c | |||
| @@ -0,0 +1,499 @@ | |||
| 1 | #include "perf.h" | ||
| 2 | #include "tests.h" | ||
| 3 | #include "debug.h" | ||
| 4 | #include "symbol.h" | ||
| 5 | #include "sort.h" | ||
| 6 | #include "evsel.h" | ||
| 7 | #include "evlist.h" | ||
| 8 | #include "machine.h" | ||
| 9 | #include "thread.h" | ||
| 10 | #include "parse-events.h" | ||
| 11 | |||
| 12 | static struct { | ||
| 13 | u32 pid; | ||
| 14 | const char *comm; | ||
| 15 | } fake_threads[] = { | ||
| 16 | { 100, "perf" }, | ||
| 17 | { 200, "perf" }, | ||
| 18 | { 300, "bash" }, | ||
| 19 | }; | ||
| 20 | |||
| 21 | static struct { | ||
| 22 | u32 pid; | ||
| 23 | u64 start; | ||
| 24 | const char *filename; | ||
| 25 | } fake_mmap_info[] = { | ||
| 26 | { 100, 0x40000, "perf" }, | ||
| 27 | { 100, 0x50000, "libc" }, | ||
| 28 | { 100, 0xf0000, "[kernel]" }, | ||
| 29 | { 200, 0x40000, "perf" }, | ||
| 30 | { 200, 0x50000, "libc" }, | ||
| 31 | { 200, 0xf0000, "[kernel]" }, | ||
| 32 | { 300, 0x40000, "bash" }, | ||
| 33 | { 300, 0x50000, "libc" }, | ||
| 34 | { 300, 0xf0000, "[kernel]" }, | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct fake_sym { | ||
| 38 | u64 start; | ||
| 39 | u64 length; | ||
| 40 | const char *name; | ||
| 41 | }; | ||
| 42 | |||
| 43 | static struct fake_sym perf_syms[] = { | ||
| 44 | { 700, 100, "main" }, | ||
| 45 | { 800, 100, "run_command" }, | ||
| 46 | { 900, 100, "cmd_record" }, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct fake_sym bash_syms[] = { | ||
| 50 | { 700, 100, "main" }, | ||
| 51 | { 800, 100, "xmalloc" }, | ||
| 52 | { 900, 100, "xfree" }, | ||
| 53 | }; | ||
| 54 | |||
| 55 | static struct fake_sym libc_syms[] = { | ||
| 56 | { 700, 100, "malloc" }, | ||
| 57 | { 800, 100, "free" }, | ||
| 58 | { 900, 100, "realloc" }, | ||
| 59 | }; | ||
| 60 | |||
| 61 | static struct fake_sym kernel_syms[] = { | ||
| 62 | { 700, 100, "schedule" }, | ||
| 63 | { 800, 100, "page_fault" }, | ||
| 64 | { 900, 100, "sys_perf_event_open" }, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static struct { | ||
| 68 | const char *dso_name; | ||
| 69 | struct fake_sym *syms; | ||
| 70 | size_t nr_syms; | ||
| 71 | } fake_symbols[] = { | ||
| 72 | { "perf", perf_syms, ARRAY_SIZE(perf_syms) }, | ||
| 73 | { "bash", bash_syms, ARRAY_SIZE(bash_syms) }, | ||
| 74 | { "libc", libc_syms, ARRAY_SIZE(libc_syms) }, | ||
| 75 | { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, | ||
| 76 | }; | ||
| 77 | |||
| 78 | static struct machine *setup_fake_machine(struct machines *machines) | ||
| 79 | { | ||
| 80 | struct machine *machine = machines__find(machines, HOST_KERNEL_ID); | ||
| 81 | size_t i; | ||
| 82 | |||
| 83 | if (machine == NULL) { | ||
| 84 | pr_debug("Not enough memory for machine setup\n"); | ||
| 85 | return NULL; | ||
| 86 | } | ||
| 87 | |||
| 88 | for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { | ||
| 89 | struct thread *thread; | ||
| 90 | |||
| 91 | thread = machine__findnew_thread(machine, fake_threads[i].pid); | ||
| 92 | if (thread == NULL) | ||
| 93 | goto out; | ||
| 94 | |||
| 95 | thread__set_comm(thread, fake_threads[i].comm); | ||
| 96 | } | ||
| 97 | |||
| 98 | for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { | ||
| 99 | union perf_event fake_mmap_event = { | ||
| 100 | .mmap = { | ||
| 101 | .header = { .misc = PERF_RECORD_MISC_USER, }, | ||
| 102 | .pid = fake_mmap_info[i].pid, | ||
| 103 | .start = fake_mmap_info[i].start, | ||
| 104 | .len = 0x1000ULL, | ||
| 105 | .pgoff = 0ULL, | ||
| 106 | }, | ||
| 107 | }; | ||
| 108 | |||
| 109 | strcpy(fake_mmap_event.mmap.filename, | ||
| 110 | fake_mmap_info[i].filename); | ||
| 111 | |||
| 112 | machine__process_mmap_event(machine, &fake_mmap_event); | ||
| 113 | } | ||
| 114 | |||
| 115 | for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { | ||
| 116 | size_t k; | ||
| 117 | struct dso *dso; | ||
| 118 | |||
| 119 | dso = __dsos__findnew(&machine->user_dsos, | ||
| 120 | fake_symbols[i].dso_name); | ||
| 121 | if (dso == NULL) | ||
| 122 | goto out; | ||
| 123 | |||
| 124 | /* emulate dso__load() */ | ||
| 125 | dso__set_loaded(dso, MAP__FUNCTION); | ||
| 126 | |||
| 127 | for (k = 0; k < fake_symbols[i].nr_syms; k++) { | ||
| 128 | struct symbol *sym; | ||
| 129 | struct fake_sym *fsym = &fake_symbols[i].syms[k]; | ||
| 130 | |||
| 131 | sym = symbol__new(fsym->start, fsym->length, | ||
| 132 | STB_GLOBAL, fsym->name); | ||
| 133 | if (sym == NULL) | ||
| 134 | goto out; | ||
| 135 | |||
| 136 | symbols__insert(&dso->symbols[MAP__FUNCTION], sym); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | return machine; | ||
| 141 | |||
| 142 | out: | ||
| 143 | pr_debug("Not enough memory for machine setup\n"); | ||
| 144 | machine__delete_threads(machine); | ||
| 145 | machine__delete(machine); | ||
| 146 | return NULL; | ||
| 147 | } | ||
| 148 | |||
| 149 | struct sample { | ||
| 150 | u32 pid; | ||
| 151 | u64 ip; | ||
| 152 | struct thread *thread; | ||
| 153 | struct map *map; | ||
| 154 | struct symbol *sym; | ||
| 155 | }; | ||
| 156 | |||
| 157 | static struct sample fake_common_samples[] = { | ||
| 158 | /* perf [kernel] schedule() */ | ||
| 159 | { .pid = 100, .ip = 0xf0000 + 700, }, | ||
| 160 | /* perf [perf] main() */ | ||
| 161 | { .pid = 200, .ip = 0x40000 + 700, }, | ||
| 162 | /* perf [perf] cmd_record() */ | ||
| 163 | { .pid = 200, .ip = 0x40000 + 900, }, | ||
| 164 | /* bash [bash] xmalloc() */ | ||
| 165 | { .pid = 300, .ip = 0x40000 + 800, }, | ||
| 166 | /* bash [libc] malloc() */ | ||
| 167 | { .pid = 300, .ip = 0x50000 + 700, }, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static struct sample fake_samples[][5] = { | ||
| 171 | { | ||
| 172 | /* perf [perf] run_command() */ | ||
| 173 | { .pid = 100, .ip = 0x40000 + 800, }, | ||
| 174 | /* perf [libc] malloc() */ | ||
| 175 | { .pid = 100, .ip = 0x50000 + 700, }, | ||
| 176 | /* perf [kernel] page_fault() */ | ||
| 177 | { .pid = 100, .ip = 0xf0000 + 800, }, | ||
| 178 | /* perf [kernel] sys_perf_event_open() */ | ||
| 179 | { .pid = 200, .ip = 0xf0000 + 900, }, | ||
| 180 | /* bash [libc] free() */ | ||
| 181 | { .pid = 300, .ip = 0x50000 + 800, }, | ||
| 182 | }, | ||
| 183 | { | ||
| 184 | /* perf [libc] free() */ | ||
| 185 | { .pid = 200, .ip = 0x50000 + 800, }, | ||
| 186 | /* bash [libc] malloc() */ | ||
| 187 | { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ | ||
| 188 | /* bash [bash] xfee() */ | ||
| 189 | { .pid = 300, .ip = 0x40000 + 900, }, | ||
| 190 | /* bash [libc] realloc() */ | ||
| 191 | { .pid = 300, .ip = 0x50000 + 900, }, | ||
| 192 | /* bash [kernel] page_fault() */ | ||
| 193 | { .pid = 300, .ip = 0xf0000 + 800, }, | ||
| 194 | }, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | ||
| 198 | { | ||
| 199 | struct perf_evsel *evsel; | ||
| 200 | struct addr_location al; | ||
| 201 | struct hist_entry *he; | ||
| 202 | struct perf_sample sample = { .cpu = 0, }; | ||
| 203 | size_t i = 0, k; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * each evsel will have 10 samples - 5 common and 5 distinct. | ||
| 207 | * However the second evsel also has a collapsed entry for | ||
| 208 | * "bash [libc] malloc" so total 9 entries will be in the tree. | ||
| 209 | */ | ||
| 210 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 211 | for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { | ||
| 212 | const union perf_event event = { | ||
| 213 | .ip = { | ||
| 214 | .header = { | ||
| 215 | .misc = PERF_RECORD_MISC_USER, | ||
| 216 | }, | ||
| 217 | .pid = fake_common_samples[k].pid, | ||
| 218 | .ip = fake_common_samples[k].ip, | ||
| 219 | }, | ||
| 220 | }; | ||
| 221 | |||
| 222 | if (perf_event__preprocess_sample(&event, machine, &al, | ||
| 223 | &sample, 0) < 0) | ||
| 224 | goto out; | ||
| 225 | |||
| 226 | he = __hists__add_entry(&evsel->hists, &al, NULL, 1); | ||
| 227 | if (he == NULL) | ||
| 228 | goto out; | ||
| 229 | |||
| 230 | fake_common_samples[k].thread = al.thread; | ||
| 231 | fake_common_samples[k].map = al.map; | ||
| 232 | fake_common_samples[k].sym = al.sym; | ||
| 233 | } | ||
| 234 | |||
| 235 | for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { | ||
| 236 | const union perf_event event = { | ||
| 237 | .ip = { | ||
| 238 | .header = { | ||
| 239 | .misc = PERF_RECORD_MISC_USER, | ||
| 240 | }, | ||
| 241 | .pid = fake_samples[i][k].pid, | ||
| 242 | .ip = fake_samples[i][k].ip, | ||
| 243 | }, | ||
| 244 | }; | ||
| 245 | |||
| 246 | if (perf_event__preprocess_sample(&event, machine, &al, | ||
| 247 | &sample, 0) < 0) | ||
| 248 | goto out; | ||
| 249 | |||
| 250 | he = __hists__add_entry(&evsel->hists, &al, NULL, 1); | ||
| 251 | if (he == NULL) | ||
| 252 | goto out; | ||
| 253 | |||
| 254 | fake_samples[i][k].thread = al.thread; | ||
| 255 | fake_samples[i][k].map = al.map; | ||
| 256 | fake_samples[i][k].sym = al.sym; | ||
| 257 | } | ||
| 258 | i++; | ||
| 259 | } | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | |||
| 263 | out: | ||
| 264 | pr_debug("Not enough memory for adding a hist entry\n"); | ||
| 265 | return -1; | ||
| 266 | } | ||
| 267 | |||
| 268 | static int find_sample(struct sample *samples, size_t nr_samples, | ||
| 269 | struct thread *t, struct map *m, struct symbol *s) | ||
| 270 | { | ||
| 271 | while (nr_samples--) { | ||
| 272 | if (samples->thread == t && samples->map == m && | ||
| 273 | samples->sym == s) | ||
| 274 | return 1; | ||
| 275 | samples++; | ||
| 276 | } | ||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int __validate_match(struct hists *hists) | ||
| 281 | { | ||
| 282 | size_t count = 0; | ||
| 283 | struct rb_root *root; | ||
| 284 | struct rb_node *node; | ||
| 285 | |||
| 286 | /* | ||
| 287 | * Only entries from fake_common_samples should have a pair. | ||
| 288 | */ | ||
| 289 | if (sort__need_collapse) | ||
| 290 | root = &hists->entries_collapsed; | ||
| 291 | else | ||
| 292 | root = hists->entries_in; | ||
| 293 | |||
| 294 | node = rb_first(root); | ||
| 295 | while (node) { | ||
| 296 | struct hist_entry *he; | ||
| 297 | |||
| 298 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
| 299 | |||
| 300 | if (hist_entry__has_pairs(he)) { | ||
| 301 | if (find_sample(fake_common_samples, | ||
| 302 | ARRAY_SIZE(fake_common_samples), | ||
| 303 | he->thread, he->ms.map, he->ms.sym)) { | ||
| 304 | count++; | ||
| 305 | } else { | ||
| 306 | pr_debug("Can't find the matched entry\n"); | ||
| 307 | return -1; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | node = rb_next(node); | ||
| 312 | } | ||
| 313 | |||
| 314 | if (count != ARRAY_SIZE(fake_common_samples)) { | ||
| 315 | pr_debug("Invalid count for matched entries: %zd of %zd\n", | ||
| 316 | count, ARRAY_SIZE(fake_common_samples)); | ||
| 317 | return -1; | ||
| 318 | } | ||
| 319 | |||
| 320 | return 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | static int validate_match(struct hists *leader, struct hists *other) | ||
| 324 | { | ||
| 325 | return __validate_match(leader) || __validate_match(other); | ||
| 326 | } | ||
| 327 | |||
| 328 | static int __validate_link(struct hists *hists, int idx) | ||
| 329 | { | ||
| 330 | size_t count = 0; | ||
| 331 | size_t count_pair = 0; | ||
| 332 | size_t count_dummy = 0; | ||
| 333 | struct rb_root *root; | ||
| 334 | struct rb_node *node; | ||
| 335 | |||
| 336 | /* | ||
| 337 | * Leader hists (idx = 0) will have dummy entries from other, | ||
| 338 | * and some entries will have no pair. However every entry | ||
| 339 | * in other hists should have (dummy) pair. | ||
| 340 | */ | ||
| 341 | if (sort__need_collapse) | ||
| 342 | root = &hists->entries_collapsed; | ||
| 343 | else | ||
| 344 | root = hists->entries_in; | ||
| 345 | |||
| 346 | node = rb_first(root); | ||
| 347 | while (node) { | ||
| 348 | struct hist_entry *he; | ||
| 349 | |||
| 350 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
| 351 | |||
| 352 | if (hist_entry__has_pairs(he)) { | ||
| 353 | if (!find_sample(fake_common_samples, | ||
| 354 | ARRAY_SIZE(fake_common_samples), | ||
| 355 | he->thread, he->ms.map, he->ms.sym) && | ||
| 356 | !find_sample(fake_samples[idx], | ||
| 357 | ARRAY_SIZE(fake_samples[idx]), | ||
| 358 | he->thread, he->ms.map, he->ms.sym)) { | ||
| 359 | count_dummy++; | ||
| 360 | } | ||
| 361 | count_pair++; | ||
| 362 | } else if (idx) { | ||
| 363 | pr_debug("A entry from the other hists should have pair\n"); | ||
| 364 | return -1; | ||
| 365 | } | ||
| 366 | |||
| 367 | count++; | ||
| 368 | node = rb_next(node); | ||
| 369 | } | ||
| 370 | |||
| 371 | /* | ||
| 372 | * Note that we have a entry collapsed in the other (idx = 1) hists. | ||
| 373 | */ | ||
| 374 | if (idx == 0) { | ||
| 375 | if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) { | ||
| 376 | pr_debug("Invalid count of dummy entries: %zd of %zd\n", | ||
| 377 | count_dummy, ARRAY_SIZE(fake_samples[1]) - 1); | ||
| 378 | return -1; | ||
| 379 | } | ||
| 380 | if (count != count_pair + ARRAY_SIZE(fake_samples[0])) { | ||
| 381 | pr_debug("Invalid count of total leader entries: %zd of %zd\n", | ||
| 382 | count, count_pair + ARRAY_SIZE(fake_samples[0])); | ||
| 383 | return -1; | ||
| 384 | } | ||
| 385 | } else { | ||
| 386 | if (count != count_pair) { | ||
| 387 | pr_debug("Invalid count of total other entries: %zd of %zd\n", | ||
| 388 | count, count_pair); | ||
| 389 | return -1; | ||
| 390 | } | ||
| 391 | if (count_dummy > 0) { | ||
| 392 | pr_debug("Other hists should not have dummy entries: %zd\n", | ||
| 393 | count_dummy); | ||
| 394 | return -1; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int validate_link(struct hists *leader, struct hists *other) | ||
| 402 | { | ||
| 403 | return __validate_link(leader, 0) || __validate_link(other, 1); | ||
| 404 | } | ||
| 405 | |||
| 406 | static void print_hists(struct hists *hists) | ||
| 407 | { | ||
| 408 | int i = 0; | ||
| 409 | struct rb_root *root; | ||
| 410 | struct rb_node *node; | ||
| 411 | |||
| 412 | if (sort__need_collapse) | ||
| 413 | root = &hists->entries_collapsed; | ||
| 414 | else | ||
| 415 | root = hists->entries_in; | ||
| 416 | |||
| 417 | pr_info("----- %s --------\n", __func__); | ||
| 418 | node = rb_first(root); | ||
| 419 | while (node) { | ||
| 420 | struct hist_entry *he; | ||
| 421 | |||
| 422 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
| 423 | |||
| 424 | pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", | ||
| 425 | i, he->thread->comm, he->ms.map->dso->short_name, | ||
| 426 | he->ms.sym->name, he->stat.period); | ||
| 427 | |||
| 428 | i++; | ||
| 429 | node = rb_next(node); | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | int test__hists_link(void) | ||
| 434 | { | ||
| 435 | int err = -1; | ||
| 436 | struct machines machines; | ||
| 437 | struct machine *machine = NULL; | ||
| 438 | struct perf_evsel *evsel, *first; | ||
| 439 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | ||
| 440 | |||
| 441 | if (evlist == NULL) | ||
| 442 | return -ENOMEM; | ||
| 443 | |||
| 444 | err = parse_events(evlist, "cpu-clock"); | ||
| 445 | if (err) | ||
| 446 | goto out; | ||
| 447 | err = parse_events(evlist, "task-clock"); | ||
| 448 | if (err) | ||
| 449 | goto out; | ||
| 450 | |||
| 451 | /* default sort order (comm,dso,sym) will be used */ | ||
| 452 | setup_sorting(NULL, NULL); | ||
| 453 | |||
| 454 | machines__init(&machines); | ||
| 455 | |||
| 456 | /* setup threads/dso/map/symbols also */ | ||
| 457 | machine = setup_fake_machine(&machines); | ||
| 458 | if (!machine) | ||
| 459 | goto out; | ||
| 460 | |||
| 461 | if (verbose > 1) | ||
| 462 | machine__fprintf(machine, stderr); | ||
| 463 | |||
| 464 | /* process sample events */ | ||
| 465 | err = add_hist_entries(evlist, machine); | ||
| 466 | if (err < 0) | ||
| 467 | goto out; | ||
| 468 | |||
| 469 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 470 | hists__collapse_resort(&evsel->hists); | ||
| 471 | |||
| 472 | if (verbose > 2) | ||
| 473 | print_hists(&evsel->hists); | ||
| 474 | } | ||
| 475 | |||
| 476 | first = perf_evlist__first(evlist); | ||
| 477 | evsel = perf_evlist__last(evlist); | ||
| 478 | |||
| 479 | /* match common entries */ | ||
| 480 | hists__match(&first->hists, &evsel->hists); | ||
| 481 | err = validate_match(&first->hists, &evsel->hists); | ||
| 482 | if (err) | ||
| 483 | goto out; | ||
| 484 | |||
| 485 | /* link common and/or dummy entries */ | ||
| 486 | hists__link(&first->hists, &evsel->hists); | ||
| 487 | err = validate_link(&first->hists, &evsel->hists); | ||
| 488 | if (err) | ||
| 489 | goto out; | ||
| 490 | |||
| 491 | err = 0; | ||
| 492 | |||
| 493 | out: | ||
| 494 | /* tear down everything */ | ||
| 495 | perf_evlist__delete(evlist); | ||
| 496 | machines__exit(&machines); | ||
| 497 | |||
| 498 | return err; | ||
| 499 | } | ||
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 294ffddfbf42..20acaff295d2 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include "evsel.h" | 3 | #include "evsel.h" |
| 4 | #include "evlist.h" | 4 | #include "evlist.h" |
| 5 | #include "sysfs.h" | 5 | #include "sysfs.h" |
| 6 | #include "debugfs.h" | ||
| 6 | #include "tests.h" | 7 | #include "tests.h" |
| 7 | #include <linux/hw_breakpoint.h> | 8 | #include <linux/hw_breakpoint.h> |
| 8 | 9 | ||
| @@ -463,10 +464,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist) | |||
| 463 | 464 | ||
| 464 | static int test__checkterms_simple(struct list_head *terms) | 465 | static int test__checkterms_simple(struct list_head *terms) |
| 465 | { | 466 | { |
| 466 | struct parse_events__term *term; | 467 | struct parse_events_term *term; |
| 467 | 468 | ||
| 468 | /* config=10 */ | 469 | /* config=10 */ |
| 469 | term = list_entry(terms->next, struct parse_events__term, list); | 470 | term = list_entry(terms->next, struct parse_events_term, list); |
| 470 | TEST_ASSERT_VAL("wrong type term", | 471 | TEST_ASSERT_VAL("wrong type term", |
| 471 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | 472 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); |
| 472 | TEST_ASSERT_VAL("wrong type val", | 473 | TEST_ASSERT_VAL("wrong type val", |
| @@ -475,7 +476,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
| 475 | TEST_ASSERT_VAL("wrong config", !term->config); | 476 | TEST_ASSERT_VAL("wrong config", !term->config); |
| 476 | 477 | ||
| 477 | /* config1 */ | 478 | /* config1 */ |
| 478 | term = list_entry(term->list.next, struct parse_events__term, list); | 479 | term = list_entry(term->list.next, struct parse_events_term, list); |
| 479 | TEST_ASSERT_VAL("wrong type term", | 480 | TEST_ASSERT_VAL("wrong type term", |
| 480 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | 481 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); |
| 481 | TEST_ASSERT_VAL("wrong type val", | 482 | TEST_ASSERT_VAL("wrong type val", |
| @@ -484,7 +485,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
| 484 | TEST_ASSERT_VAL("wrong config", !term->config); | 485 | TEST_ASSERT_VAL("wrong config", !term->config); |
| 485 | 486 | ||
| 486 | /* config2=3 */ | 487 | /* config2=3 */ |
| 487 | term = list_entry(term->list.next, struct parse_events__term, list); | 488 | term = list_entry(term->list.next, struct parse_events_term, list); |
| 488 | TEST_ASSERT_VAL("wrong type term", | 489 | TEST_ASSERT_VAL("wrong type term", |
| 489 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | 490 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); |
| 490 | TEST_ASSERT_VAL("wrong type val", | 491 | TEST_ASSERT_VAL("wrong type val", |
| @@ -493,7 +494,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
| 493 | TEST_ASSERT_VAL("wrong config", !term->config); | 494 | TEST_ASSERT_VAL("wrong config", !term->config); |
| 494 | 495 | ||
| 495 | /* umask=1*/ | 496 | /* umask=1*/ |
| 496 | term = list_entry(term->list.next, struct parse_events__term, list); | 497 | term = list_entry(term->list.next, struct parse_events_term, list); |
| 497 | TEST_ASSERT_VAL("wrong type term", | 498 | TEST_ASSERT_VAL("wrong type term", |
| 498 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | 499 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); |
| 499 | TEST_ASSERT_VAL("wrong type val", | 500 | TEST_ASSERT_VAL("wrong type val", |
| @@ -782,13 +783,70 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
| 782 | return 0; | 783 | return 0; |
| 783 | } | 784 | } |
| 784 | 785 | ||
| 785 | struct test__event_st { | 786 | static int count_tracepoints(void) |
| 787 | { | ||
| 788 | char events_path[PATH_MAX]; | ||
| 789 | struct dirent *events_ent; | ||
| 790 | DIR *events_dir; | ||
| 791 | int cnt = 0; | ||
| 792 | |||
| 793 | scnprintf(events_path, PATH_MAX, "%s/tracing/events", | ||
| 794 | debugfs_find_mountpoint()); | ||
| 795 | |||
| 796 | events_dir = opendir(events_path); | ||
| 797 | |||
| 798 | TEST_ASSERT_VAL("Can't open events dir", events_dir); | ||
| 799 | |||
| 800 | while ((events_ent = readdir(events_dir))) { | ||
| 801 | char sys_path[PATH_MAX]; | ||
| 802 | struct dirent *sys_ent; | ||
| 803 | DIR *sys_dir; | ||
| 804 | |||
| 805 | if (!strcmp(events_ent->d_name, ".") | ||
| 806 | || !strcmp(events_ent->d_name, "..") | ||
| 807 | || !strcmp(events_ent->d_name, "enable") | ||
| 808 | || !strcmp(events_ent->d_name, "header_event") | ||
| 809 | || !strcmp(events_ent->d_name, "header_page")) | ||
| 810 | continue; | ||
| 811 | |||
| 812 | scnprintf(sys_path, PATH_MAX, "%s/%s", | ||
| 813 | events_path, events_ent->d_name); | ||
| 814 | |||
| 815 | sys_dir = opendir(sys_path); | ||
| 816 | TEST_ASSERT_VAL("Can't open sys dir", sys_dir); | ||
| 817 | |||
| 818 | while ((sys_ent = readdir(sys_dir))) { | ||
| 819 | if (!strcmp(sys_ent->d_name, ".") | ||
| 820 | || !strcmp(sys_ent->d_name, "..") | ||
| 821 | || !strcmp(sys_ent->d_name, "enable") | ||
| 822 | || !strcmp(sys_ent->d_name, "filter")) | ||
| 823 | continue; | ||
| 824 | |||
| 825 | cnt++; | ||
| 826 | } | ||
| 827 | |||
| 828 | closedir(sys_dir); | ||
| 829 | } | ||
| 830 | |||
| 831 | closedir(events_dir); | ||
| 832 | return cnt; | ||
| 833 | } | ||
| 834 | |||
| 835 | static int test__all_tracepoints(struct perf_evlist *evlist) | ||
| 836 | { | ||
| 837 | TEST_ASSERT_VAL("wrong events count", | ||
| 838 | count_tracepoints() == evlist->nr_entries); | ||
| 839 | |||
| 840 | return test__checkevent_tracepoint_multi(evlist); | ||
| 841 | } | ||
| 842 | |||
| 843 | struct evlist_test { | ||
| 786 | const char *name; | 844 | const char *name; |
| 787 | __u32 type; | 845 | __u32 type; |
| 788 | int (*check)(struct perf_evlist *evlist); | 846 | int (*check)(struct perf_evlist *evlist); |
| 789 | }; | 847 | }; |
| 790 | 848 | ||
| 791 | static struct test__event_st test__events[] = { | 849 | static struct evlist_test test__events[] = { |
| 792 | [0] = { | 850 | [0] = { |
| 793 | .name = "syscalls:sys_enter_open", | 851 | .name = "syscalls:sys_enter_open", |
| 794 | .check = test__checkevent_tracepoint, | 852 | .check = test__checkevent_tracepoint, |
| @@ -921,9 +979,13 @@ static struct test__event_st test__events[] = { | |||
| 921 | .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", | 979 | .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", |
| 922 | .check = test__group5, | 980 | .check = test__group5, |
| 923 | }, | 981 | }, |
| 982 | [33] = { | ||
| 983 | .name = "*:*", | ||
| 984 | .check = test__all_tracepoints, | ||
| 985 | }, | ||
| 924 | }; | 986 | }; |
| 925 | 987 | ||
| 926 | static struct test__event_st test__events_pmu[] = { | 988 | static struct evlist_test test__events_pmu[] = { |
| 927 | [0] = { | 989 | [0] = { |
| 928 | .name = "cpu/config=10,config1,config2=3,period=1000/u", | 990 | .name = "cpu/config=10,config1,config2=3,period=1000/u", |
| 929 | .check = test__checkevent_pmu, | 991 | .check = test__checkevent_pmu, |
| @@ -934,20 +996,20 @@ static struct test__event_st test__events_pmu[] = { | |||
| 934 | }, | 996 | }, |
| 935 | }; | 997 | }; |
| 936 | 998 | ||
| 937 | struct test__term { | 999 | struct terms_test { |
| 938 | const char *str; | 1000 | const char *str; |
| 939 | __u32 type; | 1001 | __u32 type; |
| 940 | int (*check)(struct list_head *terms); | 1002 | int (*check)(struct list_head *terms); |
| 941 | }; | 1003 | }; |
| 942 | 1004 | ||
| 943 | static struct test__term test__terms[] = { | 1005 | static struct terms_test test__terms[] = { |
| 944 | [0] = { | 1006 | [0] = { |
| 945 | .str = "config=10,config1,config2=3,umask=1", | 1007 | .str = "config=10,config1,config2=3,umask=1", |
| 946 | .check = test__checkterms_simple, | 1008 | .check = test__checkterms_simple, |
| 947 | }, | 1009 | }, |
| 948 | }; | 1010 | }; |
| 949 | 1011 | ||
| 950 | static int test_event(struct test__event_st *e) | 1012 | static int test_event(struct evlist_test *e) |
| 951 | { | 1013 | { |
| 952 | struct perf_evlist *evlist; | 1014 | struct perf_evlist *evlist; |
| 953 | int ret; | 1015 | int ret; |
| @@ -956,7 +1018,7 @@ static int test_event(struct test__event_st *e) | |||
| 956 | if (evlist == NULL) | 1018 | if (evlist == NULL) |
| 957 | return -ENOMEM; | 1019 | return -ENOMEM; |
| 958 | 1020 | ||
| 959 | ret = parse_events(evlist, e->name, 0); | 1021 | ret = parse_events(evlist, e->name); |
| 960 | if (ret) { | 1022 | if (ret) { |
| 961 | pr_debug("failed to parse event '%s', err %d\n", | 1023 | pr_debug("failed to parse event '%s', err %d\n", |
| 962 | e->name, ret); | 1024 | e->name, ret); |
| @@ -969,13 +1031,13 @@ static int test_event(struct test__event_st *e) | |||
| 969 | return ret; | 1031 | return ret; |
| 970 | } | 1032 | } |
| 971 | 1033 | ||
| 972 | static int test_events(struct test__event_st *events, unsigned cnt) | 1034 | static int test_events(struct evlist_test *events, unsigned cnt) |
| 973 | { | 1035 | { |
| 974 | int ret1, ret2 = 0; | 1036 | int ret1, ret2 = 0; |
| 975 | unsigned i; | 1037 | unsigned i; |
| 976 | 1038 | ||
| 977 | for (i = 0; i < cnt; i++) { | 1039 | for (i = 0; i < cnt; i++) { |
| 978 | struct test__event_st *e = &events[i]; | 1040 | struct evlist_test *e = &events[i]; |
| 979 | 1041 | ||
| 980 | pr_debug("running test %d '%s'\n", i, e->name); | 1042 | pr_debug("running test %d '%s'\n", i, e->name); |
| 981 | ret1 = test_event(e); | 1043 | ret1 = test_event(e); |
| @@ -986,7 +1048,7 @@ static int test_events(struct test__event_st *events, unsigned cnt) | |||
| 986 | return ret2; | 1048 | return ret2; |
| 987 | } | 1049 | } |
| 988 | 1050 | ||
| 989 | static int test_term(struct test__term *t) | 1051 | static int test_term(struct terms_test *t) |
| 990 | { | 1052 | { |
| 991 | struct list_head *terms; | 1053 | struct list_head *terms; |
| 992 | int ret; | 1054 | int ret; |
| @@ -1010,13 +1072,13 @@ static int test_term(struct test__term *t) | |||
| 1010 | return ret; | 1072 | return ret; |
| 1011 | } | 1073 | } |
| 1012 | 1074 | ||
| 1013 | static int test_terms(struct test__term *terms, unsigned cnt) | 1075 | static int test_terms(struct terms_test *terms, unsigned cnt) |
| 1014 | { | 1076 | { |
| 1015 | int ret = 0; | 1077 | int ret = 0; |
| 1016 | unsigned i; | 1078 | unsigned i; |
| 1017 | 1079 | ||
| 1018 | for (i = 0; i < cnt; i++) { | 1080 | for (i = 0; i < cnt; i++) { |
| 1019 | struct test__term *t = &terms[i]; | 1081 | struct terms_test *t = &terms[i]; |
| 1020 | 1082 | ||
| 1021 | pr_debug("running test %d '%s'\n", i, t->str); | 1083 | pr_debug("running test %d '%s'\n", i, t->str); |
| 1022 | ret = test_term(t); | 1084 | ret = test_term(t); |
| @@ -1067,7 +1129,7 @@ static int test_pmu_events(void) | |||
| 1067 | 1129 | ||
| 1068 | while (!ret && (ent = readdir(dir))) { | 1130 | while (!ret && (ent = readdir(dir))) { |
| 1069 | #define MAX_NAME 100 | 1131 | #define MAX_NAME 100 |
| 1070 | struct test__event_st e; | 1132 | struct evlist_test e; |
| 1071 | char name[MAX_NAME]; | 1133 | char name[MAX_NAME]; |
| 1072 | 1134 | ||
| 1073 | if (!strcmp(ent->d_name, ".") || | 1135 | if (!strcmp(ent->d_name, ".") || |
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index a5f379863b8f..12b322fa3475 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c | |||
| @@ -19,10 +19,8 @@ static struct test_format { | |||
| 19 | { "krava23", "config2:28-29,38\n", }, | 19 | { "krava23", "config2:28-29,38\n", }, |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) | ||
| 23 | |||
| 24 | /* Simulated users input. */ | 22 | /* Simulated users input. */ |
| 25 | static struct parse_events__term test_terms[] = { | 23 | static struct parse_events_term test_terms[] = { |
| 26 | { | 24 | { |
| 27 | .config = (char *) "krava01", | 25 | .config = (char *) "krava01", |
| 28 | .val.num = 15, | 26 | .val.num = 15, |
| @@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = { | |||
| 78 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | 76 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, |
| 79 | }, | 77 | }, |
| 80 | }; | 78 | }; |
| 81 | #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) | ||
| 82 | 79 | ||
| 83 | /* | 80 | /* |
| 84 | * Prepare format directory data, exported by kernel | 81 | * Prepare format directory data, exported by kernel |
| @@ -93,7 +90,7 @@ static char *test_format_dir_get(void) | |||
| 93 | if (!mkdtemp(dir)) | 90 | if (!mkdtemp(dir)) |
| 94 | return NULL; | 91 | return NULL; |
| 95 | 92 | ||
| 96 | for (i = 0; i < TEST_FORMATS_CNT; i++) { | 93 | for (i = 0; i < ARRAY_SIZE(test_formats); i++) { |
| 97 | static char name[PATH_MAX]; | 94 | static char name[PATH_MAX]; |
| 98 | struct test_format *format = &test_formats[i]; | 95 | struct test_format *format = &test_formats[i]; |
| 99 | FILE *file; | 96 | FILE *file; |
| @@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void) | |||
| 130 | static LIST_HEAD(terms); | 127 | static LIST_HEAD(terms); |
| 131 | unsigned int i; | 128 | unsigned int i; |
| 132 | 129 | ||
| 133 | for (i = 0; i < TERMS_CNT; i++) | 130 | for (i = 0; i < ARRAY_SIZE(test_terms); i++) |
| 134 | list_add_tail(&test_terms[i].list, &terms); | 131 | list_add_tail(&test_terms[i].list, &terms); |
| 135 | 132 | ||
| 136 | return &terms; | 133 | return &terms; |
| 137 | } | 134 | } |
| 138 | 135 | ||
| 139 | #undef TERMS_CNT | ||
| 140 | |||
| 141 | int test__pmu(void) | 136 | int test__pmu(void) |
| 142 | { | 137 | { |
| 143 | char *format = test_format_dir_get(); | 138 | char *format = test_format_dir_get(); |
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c new file mode 100644 index 000000000000..7760277c6def --- /dev/null +++ b/tools/perf/tests/python-use.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Just test if we can load the python binding. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | #include "tests.h" | ||
| 8 | |||
| 9 | extern int verbose; | ||
| 10 | |||
| 11 | int test__python_use(void) | ||
| 12 | { | ||
| 13 | char *cmd; | ||
| 14 | int ret; | ||
| 15 | |||
| 16 | if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s", | ||
| 17 | PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0) | ||
| 18 | return -1; | ||
| 19 | |||
| 20 | ret = system(cmd) ? -1 : 0; | ||
| 21 | free(cmd); | ||
| 22 | return ret; | ||
| 23 | } | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 0fd94657960e..5de0be1ff4b6 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
| @@ -1,6 +1,12 @@ | |||
| 1 | #ifndef TESTS_H | 1 | #ifndef TESTS_H |
| 2 | #define TESTS_H | 2 | #define TESTS_H |
| 3 | 3 | ||
| 4 | enum { | ||
| 5 | TEST_OK = 0, | ||
| 6 | TEST_FAIL = -1, | ||
| 7 | TEST_SKIP = -2, | ||
| 8 | }; | ||
| 9 | |||
| 4 | /* Tests */ | 10 | /* Tests */ |
| 5 | int test__vmlinux_matches_kallsyms(void); | 11 | int test__vmlinux_matches_kallsyms(void); |
| 6 | int test__open_syscall_event(void); | 12 | int test__open_syscall_event(void); |
| @@ -15,5 +21,7 @@ int test__pmu(void); | |||
| 15 | int test__attr(void); | 21 | int test__attr(void); |
| 16 | int test__dso_data(void); | 22 | int test__dso_data(void); |
| 17 | int test__parse_events(void); | 23 | int test__parse_events(void); |
| 24 | int test__hists_link(void); | ||
| 25 | int test__python_use(void); | ||
| 18 | 26 | ||
| 19 | #endif /* TESTS_H */ | 27 | #endif /* TESTS_H */ |
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 0d1cdbee2f59..a1a8442829b4 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
| @@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void) | |||
| 101 | */ | 101 | */ |
| 102 | if (machine__load_vmlinux_path(&vmlinux, type, | 102 | if (machine__load_vmlinux_path(&vmlinux, type, |
| 103 | vmlinux_matches_kallsyms_filter) <= 0) { | 103 | vmlinux_matches_kallsyms_filter) <= 0) { |
| 104 | pr_debug("machine__load_vmlinux_path "); | 104 | pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n"); |
| 105 | err = TEST_SKIP; | ||
| 105 | goto out; | 106 | goto out; |
| 106 | } | 107 | } |
| 107 | 108 | ||
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 4aeb7d5df939..588bcb2d008b 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
| @@ -471,7 +471,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser) | |||
| 471 | return row; | 471 | return row; |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | static struct ui_browser__colorset { | 474 | static struct ui_browser_colorset { |
| 475 | const char *name, *fg, *bg; | 475 | const char *name, *fg, *bg; |
| 476 | int colorset; | 476 | int colorset; |
| 477 | } ui_browser__colorsets[] = { | 477 | } ui_browser__colorsets[] = { |
| @@ -706,7 +706,7 @@ void ui_browser__init(void) | |||
| 706 | perf_config(ui_browser__color_config, NULL); | 706 | perf_config(ui_browser__color_config, NULL); |
| 707 | 707 | ||
| 708 | while (ui_browser__colorsets[i].name) { | 708 | while (ui_browser__colorsets[i].name) { |
| 709 | struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; | 709 | struct ui_browser_colorset *c = &ui_browser__colorsets[i++]; |
| 710 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); | 710 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); |
| 711 | } | 711 | } |
| 712 | 712 | ||
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 5dab3ca96980..7dca1555c610 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
| @@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 182 | ab->selection = dl; | 182 | ab->selection = dl; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) | ||
| 186 | { | ||
| 187 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) | ||
| 188 | || !disasm_line__has_offset(dl) | ||
| 189 | || dl->ops.target.offset >= symbol__size(sym)) | ||
| 190 | return false; | ||
| 191 | |||
| 192 | return true; | ||
| 193 | } | ||
| 194 | |||
| 185 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) | 195 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) |
| 186 | { | 196 | { |
| 187 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | 197 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); |
| @@ -195,8 +205,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) | |||
| 195 | if (strstr(sym->name, "@plt")) | 205 | if (strstr(sym->name, "@plt")) |
| 196 | return; | 206 | return; |
| 197 | 207 | ||
| 198 | if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || | 208 | if (!disasm_line__is_valid_jump(cursor, sym)) |
| 199 | !disasm_line__has_offset(cursor)) | ||
| 200 | return; | 209 | return; |
| 201 | 210 | ||
| 202 | target = ab->offsets[cursor->ops.target.offset]; | 211 | target = ab->offsets[cursor->ops.target.offset]; |
| @@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser | |||
| 788 | struct disasm_line *dl = browser->offsets[offset], *dlt; | 797 | struct disasm_line *dl = browser->offsets[offset], *dlt; |
| 789 | struct browser_disasm_line *bdlt; | 798 | struct browser_disasm_line *bdlt; |
| 790 | 799 | ||
| 791 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) || | 800 | if (!disasm_line__is_valid_jump(dl, sym)) |
| 792 | !disasm_line__has_offset(dl)) | ||
| 793 | continue; | 801 | continue; |
| 794 | 802 | ||
| 795 | if (dl->ops.target.offset >= size) { | ||
| 796 | ui__error("jump to after symbol!\n" | ||
| 797 | "size: %zx, jump target: %" PRIx64, | ||
| 798 | size, dl->ops.target.offset); | ||
| 799 | continue; | ||
| 800 | } | ||
| 801 | |||
| 802 | dlt = browser->offsets[dl->ops.target.offset]; | 803 | dlt = browser->offsets[dl->ops.target.offset]; |
| 803 | /* | 804 | /* |
| 804 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we | 805 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we |
| @@ -921,11 +922,11 @@ out_free_offsets: | |||
| 921 | 922 | ||
| 922 | #define ANNOTATE_CFG(n) \ | 923 | #define ANNOTATE_CFG(n) \ |
| 923 | { .name = #n, .value = &annotate_browser__opts.n, } | 924 | { .name = #n, .value = &annotate_browser__opts.n, } |
| 924 | 925 | ||
| 925 | /* | 926 | /* |
| 926 | * Keep the entries sorted, they are bsearch'ed | 927 | * Keep the entries sorted, they are bsearch'ed |
| 927 | */ | 928 | */ |
| 928 | static struct annotate__config { | 929 | static struct annotate_config { |
| 929 | const char *name; | 930 | const char *name; |
| 930 | bool *value; | 931 | bool *value; |
| 931 | } annotate__configs[] = { | 932 | } annotate__configs[] = { |
| @@ -939,7 +940,7 @@ static struct annotate__config { | |||
| 939 | 940 | ||
| 940 | static int annotate_config__cmp(const void *name, const void *cfgp) | 941 | static int annotate_config__cmp(const void *name, const void *cfgp) |
| 941 | { | 942 | { |
| 942 | const struct annotate__config *cfg = cfgp; | 943 | const struct annotate_config *cfg = cfgp; |
| 943 | 944 | ||
| 944 | return strcmp(name, cfg->name); | 945 | return strcmp(name, cfg->name); |
| 945 | } | 946 | } |
| @@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp) | |||
| 947 | static int annotate__config(const char *var, const char *value, | 948 | static int annotate__config(const char *var, const char *value, |
| 948 | void *data __maybe_unused) | 949 | void *data __maybe_unused) |
| 949 | { | 950 | { |
| 950 | struct annotate__config *cfg; | 951 | struct annotate_config *cfg; |
| 951 | const char *name; | 952 | const char *name; |
| 952 | 953 | ||
| 953 | if (prefixcmp(var, "annotate.") != 0) | 954 | if (prefixcmp(var, "annotate.") != 0) |
| @@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value, | |||
| 955 | 956 | ||
| 956 | name = var + 9; | 957 | name = var + 9; |
| 957 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), | 958 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), |
| 958 | sizeof(struct annotate__config), annotate_config__cmp); | 959 | sizeof(struct annotate_config), annotate_config__cmp); |
| 959 | 960 | ||
| 960 | if (cfg == NULL) | 961 | if (cfg == NULL) |
| 961 | return -1; | 962 | return -1; |
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index e59ba337f494..c95012cdb438 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
| @@ -8,15 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | #include <signal.h> | 9 | #include <signal.h> |
| 10 | 10 | ||
| 11 | #define MAX_COLUMNS 32 | 11 | void perf_gtk__signal(int sig) |
| 12 | |||
| 13 | static void perf_gtk__signal(int sig) | ||
| 14 | { | 12 | { |
| 15 | perf_gtk__exit(false); | 13 | perf_gtk__exit(false); |
| 16 | psignal(sig, "perf"); | 14 | psignal(sig, "perf"); |
| 17 | } | 15 | } |
| 18 | 16 | ||
| 19 | static void perf_gtk__resize_window(GtkWidget *window) | 17 | void perf_gtk__resize_window(GtkWidget *window) |
| 20 | { | 18 | { |
| 21 | GdkRectangle rect; | 19 | GdkRectangle rect; |
| 22 | GdkScreen *screen; | 20 | GdkScreen *screen; |
| @@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window) | |||
| 36 | gtk_window_resize(GTK_WINDOW(window), width, height); | 34 | gtk_window_resize(GTK_WINDOW(window), width, height); |
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | static const char *perf_gtk__get_percent_color(double percent) | 37 | const char *perf_gtk__get_percent_color(double percent) |
| 40 | { | 38 | { |
| 41 | if (percent >= MIN_RED) | 39 | if (percent >= MIN_RED) |
| 42 | return "<span fgcolor='red'>"; | 40 | return "<span fgcolor='red'>"; |
| @@ -45,147 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent) | |||
| 45 | return NULL; | 43 | return NULL; |
| 46 | } | 44 | } |
| 47 | 45 | ||
| 48 | #define HPP__COLOR_FN(_name, _field) \ | ||
| 49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | ||
| 50 | struct hist_entry *he) \ | ||
| 51 | { \ | ||
| 52 | struct hists *hists = he->hists; \ | ||
| 53 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
| 54 | const char *markup; \ | ||
| 55 | int ret = 0; \ | ||
| 56 | \ | ||
| 57 | markup = perf_gtk__get_percent_color(percent); \ | ||
| 58 | if (markup) \ | ||
| 59 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ | ||
| 60 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \ | ||
| 61 | if (markup) \ | ||
| 62 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ | ||
| 63 | \ | ||
| 64 | return ret; \ | ||
| 65 | } | ||
| 66 | |||
| 67 | HPP__COLOR_FN(overhead, period) | ||
| 68 | HPP__COLOR_FN(overhead_sys, period_sys) | ||
| 69 | HPP__COLOR_FN(overhead_us, period_us) | ||
| 70 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | ||
| 71 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | ||
| 72 | |||
| 73 | #undef HPP__COLOR_FN | ||
| 74 | |||
| 75 | void perf_gtk__init_hpp(void) | ||
| 76 | { | ||
| 77 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
| 78 | |||
| 79 | perf_hpp__init(); | ||
| 80 | |||
| 81 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
| 82 | perf_gtk__hpp_color_overhead; | ||
| 83 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
| 84 | perf_gtk__hpp_color_overhead_sys; | ||
| 85 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
| 86 | perf_gtk__hpp_color_overhead_us; | ||
| 87 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
| 88 | perf_gtk__hpp_color_overhead_guest_sys; | ||
| 89 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
| 90 | perf_gtk__hpp_color_overhead_guest_us; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
| 94 | { | ||
| 95 | struct perf_hpp_fmt *fmt; | ||
| 96 | GType col_types[MAX_COLUMNS]; | ||
| 97 | GtkCellRenderer *renderer; | ||
| 98 | struct sort_entry *se; | ||
| 99 | GtkListStore *store; | ||
| 100 | struct rb_node *nd; | ||
| 101 | GtkWidget *view; | ||
| 102 | int col_idx; | ||
| 103 | int nr_cols; | ||
| 104 | char s[512]; | ||
| 105 | |||
| 106 | struct perf_hpp hpp = { | ||
| 107 | .buf = s, | ||
| 108 | .size = sizeof(s), | ||
| 109 | }; | ||
| 110 | |||
| 111 | nr_cols = 0; | ||
| 112 | |||
| 113 | perf_hpp__for_each_format(fmt) | ||
| 114 | col_types[nr_cols++] = G_TYPE_STRING; | ||
| 115 | |||
| 116 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 117 | if (se->elide) | ||
| 118 | continue; | ||
| 119 | |||
| 120 | col_types[nr_cols++] = G_TYPE_STRING; | ||
| 121 | } | ||
| 122 | |||
| 123 | store = gtk_list_store_newv(nr_cols, col_types); | ||
| 124 | |||
| 125 | view = gtk_tree_view_new(); | ||
| 126 | |||
| 127 | renderer = gtk_cell_renderer_text_new(); | ||
| 128 | |||
| 129 | col_idx = 0; | ||
| 130 | |||
| 131 | perf_hpp__for_each_format(fmt) { | ||
| 132 | fmt->header(&hpp); | ||
| 133 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 134 | -1, s, | ||
| 135 | renderer, "markup", | ||
| 136 | col_idx++, NULL); | ||
| 137 | } | ||
| 138 | |||
| 139 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 140 | if (se->elide) | ||
| 141 | continue; | ||
| 142 | |||
| 143 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 144 | -1, se->se_header, | ||
| 145 | renderer, "text", | ||
| 146 | col_idx++, NULL); | ||
| 147 | } | ||
| 148 | |||
| 149 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
| 150 | |||
| 151 | g_object_unref(GTK_TREE_MODEL(store)); | ||
| 152 | |||
| 153 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
| 154 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
| 155 | GtkTreeIter iter; | ||
| 156 | |||
| 157 | if (h->filtered) | ||
| 158 | continue; | ||
| 159 | |||
| 160 | gtk_list_store_append(store, &iter); | ||
| 161 | |||
| 162 | col_idx = 0; | ||
| 163 | |||
| 164 | perf_hpp__for_each_format(fmt) { | ||
| 165 | if (fmt->color) | ||
| 166 | fmt->color(&hpp, h); | ||
| 167 | else | ||
| 168 | fmt->entry(&hpp, h); | ||
| 169 | |||
| 170 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
| 171 | } | ||
| 172 | |||
| 173 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 174 | if (se->elide) | ||
| 175 | continue; | ||
| 176 | |||
| 177 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
| 178 | hists__col_len(hists, se->se_width_idx)); | ||
| 179 | |||
| 180 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | gtk_container_add(GTK_CONTAINER(window), view); | ||
| 185 | } | ||
| 186 | |||
| 187 | #ifdef HAVE_GTK_INFO_BAR | 46 | #ifdef HAVE_GTK_INFO_BAR |
| 188 | static GtkWidget *perf_gtk__setup_info_bar(void) | 47 | GtkWidget *perf_gtk__setup_info_bar(void) |
| 189 | { | 48 | { |
| 190 | GtkWidget *info_bar; | 49 | GtkWidget *info_bar; |
| 191 | GtkWidget *label; | 50 | GtkWidget *label; |
| @@ -212,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void) | |||
| 212 | } | 71 | } |
| 213 | #endif | 72 | #endif |
| 214 | 73 | ||
| 215 | static GtkWidget *perf_gtk__setup_statusbar(void) | 74 | GtkWidget *perf_gtk__setup_statusbar(void) |
| 216 | { | 75 | { |
| 217 | GtkWidget *stbar; | 76 | GtkWidget *stbar; |
| 218 | unsigned ctxid; | 77 | unsigned ctxid; |
| @@ -226,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void) | |||
| 226 | 85 | ||
| 227 | return stbar; | 86 | return stbar; |
| 228 | } | 87 | } |
| 229 | |||
| 230 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
| 231 | const char *help, | ||
| 232 | struct hist_browser_timer *hbt __maybe_unused) | ||
| 233 | { | ||
| 234 | struct perf_evsel *pos; | ||
| 235 | GtkWidget *vbox; | ||
| 236 | GtkWidget *notebook; | ||
| 237 | GtkWidget *info_bar; | ||
| 238 | GtkWidget *statbar; | ||
| 239 | GtkWidget *window; | ||
| 240 | |||
| 241 | signal(SIGSEGV, perf_gtk__signal); | ||
| 242 | signal(SIGFPE, perf_gtk__signal); | ||
| 243 | signal(SIGINT, perf_gtk__signal); | ||
| 244 | signal(SIGQUIT, perf_gtk__signal); | ||
| 245 | signal(SIGTERM, perf_gtk__signal); | ||
| 246 | |||
| 247 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
| 248 | |||
| 249 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
| 250 | |||
| 251 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
| 252 | |||
| 253 | pgctx = perf_gtk__activate_context(window); | ||
| 254 | if (!pgctx) | ||
| 255 | return -1; | ||
| 256 | |||
| 257 | vbox = gtk_vbox_new(FALSE, 0); | ||
| 258 | |||
| 259 | notebook = gtk_notebook_new(); | ||
| 260 | |||
| 261 | list_for_each_entry(pos, &evlist->entries, node) { | ||
| 262 | struct hists *hists = &pos->hists; | ||
| 263 | const char *evname = perf_evsel__name(pos); | ||
| 264 | GtkWidget *scrolled_window; | ||
| 265 | GtkWidget *tab_label; | ||
| 266 | |||
| 267 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
| 268 | |||
| 269 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
| 270 | GTK_POLICY_AUTOMATIC, | ||
| 271 | GTK_POLICY_AUTOMATIC); | ||
| 272 | |||
| 273 | perf_gtk__show_hists(scrolled_window, hists); | ||
| 274 | |||
| 275 | tab_label = gtk_label_new(evname); | ||
| 276 | |||
| 277 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
| 278 | } | ||
| 279 | |||
| 280 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
| 281 | |||
| 282 | info_bar = perf_gtk__setup_info_bar(); | ||
| 283 | if (info_bar) | ||
| 284 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
| 285 | |||
| 286 | statbar = perf_gtk__setup_statusbar(); | ||
| 287 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
| 288 | |||
| 289 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
| 290 | |||
| 291 | gtk_widget_show_all(window); | ||
| 292 | |||
| 293 | perf_gtk__resize_window(window); | ||
| 294 | |||
| 295 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
| 296 | |||
| 297 | ui_helpline__push(help); | ||
| 298 | |||
| 299 | gtk_main(); | ||
| 300 | |||
| 301 | perf_gtk__deactivate_context(&pgctx); | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | } | ||
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 856320e2cc05..5d3693754828 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h | |||
| @@ -33,7 +33,14 @@ void perf_gtk__init_helpline(void); | |||
| 33 | void perf_gtk__init_progress(void); | 33 | void perf_gtk__init_progress(void); |
| 34 | void perf_gtk__init_hpp(void); | 34 | void perf_gtk__init_hpp(void); |
| 35 | 35 | ||
| 36 | #ifndef HAVE_GTK_INFO_BAR | 36 | void perf_gtk__signal(int sig); |
| 37 | void perf_gtk__resize_window(GtkWidget *window); | ||
| 38 | const char *perf_gtk__get_percent_color(double percent); | ||
| 39 | GtkWidget *perf_gtk__setup_statusbar(void); | ||
| 40 | |||
| 41 | #ifdef HAVE_GTK_INFO_BAR | ||
| 42 | GtkWidget *perf_gtk__setup_info_bar(void); | ||
| 43 | #else | ||
| 37 | static inline GtkWidget *perf_gtk__setup_info_bar(void) | 44 | static inline GtkWidget *perf_gtk__setup_info_bar(void) |
| 38 | { | 45 | { |
| 39 | return NULL; | 46 | return NULL; |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c new file mode 100644 index 000000000000..c03da79d524f --- /dev/null +++ b/tools/perf/ui/gtk/hists.c | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | #include "../evlist.h" | ||
| 2 | #include "../cache.h" | ||
| 3 | #include "../evsel.h" | ||
| 4 | #include "../sort.h" | ||
| 5 | #include "../hist.h" | ||
| 6 | #include "../helpline.h" | ||
| 7 | #include "gtk.h" | ||
| 8 | |||
| 9 | #define MAX_COLUMNS 32 | ||
| 10 | |||
| 11 | #define HPP__COLOR_FN(_name, _field) \ | ||
| 12 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | ||
| 13 | struct hist_entry *he) \ | ||
| 14 | { \ | ||
| 15 | struct hists *hists = he->hists; \ | ||
| 16 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
| 17 | const char *markup; \ | ||
| 18 | int ret = 0; \ | ||
| 19 | \ | ||
| 20 | markup = perf_gtk__get_percent_color(percent); \ | ||
| 21 | if (markup) \ | ||
| 22 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ | ||
| 23 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \ | ||
| 24 | if (markup) \ | ||
| 25 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ | ||
| 26 | \ | ||
| 27 | return ret; \ | ||
| 28 | } | ||
| 29 | |||
| 30 | HPP__COLOR_FN(overhead, period) | ||
| 31 | HPP__COLOR_FN(overhead_sys, period_sys) | ||
| 32 | HPP__COLOR_FN(overhead_us, period_us) | ||
| 33 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | ||
| 34 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | ||
| 35 | |||
| 36 | #undef HPP__COLOR_FN | ||
| 37 | |||
| 38 | |||
| 39 | void perf_gtk__init_hpp(void) | ||
| 40 | { | ||
| 41 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
| 42 | |||
| 43 | perf_hpp__init(); | ||
| 44 | |||
| 45 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
| 46 | perf_gtk__hpp_color_overhead; | ||
| 47 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
| 48 | perf_gtk__hpp_color_overhead_sys; | ||
| 49 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
| 50 | perf_gtk__hpp_color_overhead_us; | ||
| 51 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
| 52 | perf_gtk__hpp_color_overhead_guest_sys; | ||
| 53 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
| 54 | perf_gtk__hpp_color_overhead_guest_us; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
| 58 | { | ||
| 59 | struct perf_hpp_fmt *fmt; | ||
| 60 | GType col_types[MAX_COLUMNS]; | ||
| 61 | GtkCellRenderer *renderer; | ||
| 62 | struct sort_entry *se; | ||
| 63 | GtkListStore *store; | ||
| 64 | struct rb_node *nd; | ||
| 65 | GtkWidget *view; | ||
| 66 | int col_idx; | ||
| 67 | int nr_cols; | ||
| 68 | char s[512]; | ||
| 69 | |||
| 70 | struct perf_hpp hpp = { | ||
| 71 | .buf = s, | ||
| 72 | .size = sizeof(s), | ||
| 73 | }; | ||
| 74 | |||
| 75 | nr_cols = 0; | ||
| 76 | |||
| 77 | perf_hpp__for_each_format(fmt) | ||
| 78 | col_types[nr_cols++] = G_TYPE_STRING; | ||
| 79 | |||
| 80 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 81 | if (se->elide) | ||
| 82 | continue; | ||
| 83 | |||
| 84 | col_types[nr_cols++] = G_TYPE_STRING; | ||
| 85 | } | ||
| 86 | |||
| 87 | store = gtk_list_store_newv(nr_cols, col_types); | ||
| 88 | |||
| 89 | view = gtk_tree_view_new(); | ||
| 90 | |||
| 91 | renderer = gtk_cell_renderer_text_new(); | ||
| 92 | |||
| 93 | col_idx = 0; | ||
| 94 | |||
| 95 | perf_hpp__for_each_format(fmt) { | ||
| 96 | fmt->header(&hpp); | ||
| 97 | |||
| 98 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 99 | -1, s, | ||
| 100 | renderer, "markup", | ||
| 101 | col_idx++, NULL); | ||
| 102 | } | ||
| 103 | |||
| 104 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 105 | if (se->elide) | ||
| 106 | continue; | ||
| 107 | |||
| 108 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 109 | -1, se->se_header, | ||
| 110 | renderer, "text", | ||
| 111 | col_idx++, NULL); | ||
| 112 | } | ||
| 113 | |||
| 114 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
| 115 | |||
| 116 | g_object_unref(GTK_TREE_MODEL(store)); | ||
| 117 | |||
| 118 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
| 119 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
| 120 | GtkTreeIter iter; | ||
| 121 | |||
| 122 | if (h->filtered) | ||
| 123 | continue; | ||
| 124 | |||
| 125 | gtk_list_store_append(store, &iter); | ||
| 126 | |||
| 127 | col_idx = 0; | ||
| 128 | |||
| 129 | perf_hpp__for_each_format(fmt) { | ||
| 130 | if (fmt->color) | ||
| 131 | fmt->color(&hpp, h); | ||
| 132 | else | ||
| 133 | fmt->entry(&hpp, h); | ||
| 134 | |||
| 135 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
| 136 | } | ||
| 137 | |||
| 138 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
| 139 | if (se->elide) | ||
| 140 | continue; | ||
| 141 | |||
| 142 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
| 143 | hists__col_len(hists, se->se_width_idx)); | ||
| 144 | |||
| 145 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | gtk_container_add(GTK_CONTAINER(window), view); | ||
| 150 | } | ||
| 151 | |||
| 152 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
| 153 | const char *help, | ||
| 154 | struct hist_browser_timer *hbt __maybe_unused) | ||
| 155 | { | ||
| 156 | struct perf_evsel *pos; | ||
| 157 | GtkWidget *vbox; | ||
| 158 | GtkWidget *notebook; | ||
| 159 | GtkWidget *info_bar; | ||
| 160 | GtkWidget *statbar; | ||
| 161 | GtkWidget *window; | ||
| 162 | |||
| 163 | signal(SIGSEGV, perf_gtk__signal); | ||
| 164 | signal(SIGFPE, perf_gtk__signal); | ||
| 165 | signal(SIGINT, perf_gtk__signal); | ||
| 166 | signal(SIGQUIT, perf_gtk__signal); | ||
| 167 | signal(SIGTERM, perf_gtk__signal); | ||
| 168 | |||
| 169 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
| 170 | |||
| 171 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
| 172 | |||
| 173 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
| 174 | |||
| 175 | pgctx = perf_gtk__activate_context(window); | ||
| 176 | if (!pgctx) | ||
| 177 | return -1; | ||
| 178 | |||
| 179 | vbox = gtk_vbox_new(FALSE, 0); | ||
| 180 | |||
| 181 | notebook = gtk_notebook_new(); | ||
| 182 | |||
| 183 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
| 184 | |||
| 185 | info_bar = perf_gtk__setup_info_bar(); | ||
| 186 | if (info_bar) | ||
| 187 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
| 188 | |||
| 189 | statbar = perf_gtk__setup_statusbar(); | ||
| 190 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
| 191 | |||
| 192 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
| 193 | |||
| 194 | list_for_each_entry(pos, &evlist->entries, node) { | ||
| 195 | struct hists *hists = &pos->hists; | ||
| 196 | const char *evname = perf_evsel__name(pos); | ||
| 197 | GtkWidget *scrolled_window; | ||
| 198 | GtkWidget *tab_label; | ||
| 199 | |||
| 200 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
| 201 | |||
| 202 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
| 203 | GTK_POLICY_AUTOMATIC, | ||
| 204 | GTK_POLICY_AUTOMATIC); | ||
| 205 | |||
| 206 | perf_gtk__show_hists(scrolled_window, hists); | ||
| 207 | |||
| 208 | tab_label = gtk_label_new(evname); | ||
| 209 | |||
| 210 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
| 211 | } | ||
| 212 | |||
| 213 | gtk_widget_show_all(window); | ||
| 214 | |||
| 215 | perf_gtk__resize_window(window); | ||
| 216 | |||
| 217 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
| 218 | |||
| 219 | ui_helpline__push(help); | ||
| 220 | |||
| 221 | gtk_main(); | ||
| 222 | |||
| 223 | perf_gtk__deactivate_context(&pgctx); | ||
| 224 | |||
| 225 | return 0; | ||
| 226 | } | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 0eae3b2c32f2..f9798298e3e0 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
| @@ -459,7 +459,7 @@ out: | |||
| 459 | return ret; | 459 | return ret; |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | 462 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) |
| 463 | { | 463 | { |
| 464 | int i; | 464 | int i; |
| 465 | size_t ret = 0; | 465 | size_t ret = 0; |
| @@ -467,7 +467,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
| 467 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 467 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
| 468 | const char *name; | 468 | const char *name; |
| 469 | 469 | ||
| 470 | if (hists->stats.nr_events[i] == 0) | 470 | if (stats->nr_events[i] == 0) |
| 471 | continue; | 471 | continue; |
| 472 | 472 | ||
| 473 | name = perf_event__name(i); | 473 | name = perf_event__name(i); |
| @@ -475,7 +475,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
| 475 | continue; | 475 | continue; |
| 476 | 476 | ||
| 477 | ret += fprintf(fp, "%16s events: %10d\n", name, | 477 | ret += fprintf(fp, "%16s events: %10d\n", name, |
| 478 | hists->stats.nr_events[i]); | 478 | stats->nr_events[i]); |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | return ret; | 481 | return ret; |
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 3014a7cd5271..e3e0a963d03a 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c | |||
| @@ -52,17 +52,6 @@ int ui__warning(const char *format, ...) | |||
| 52 | return ret; | 52 | return ret; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | int ui__error_paranoid(void) | ||
| 56 | { | ||
| 57 | return ui__error("Permission error - are you root?\n" | ||
| 58 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
| 59 | " -1 - Not paranoid at all\n" | ||
| 60 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
| 61 | " 1 - Disallow cpu events for unpriv\n" | ||
| 62 | " 2 - Disallow kernel profiling for unpriv\n"); | ||
| 63 | } | ||
| 64 | |||
| 65 | |||
| 66 | /** | 55 | /** |
| 67 | * perf_error__register - Register error logging functions | 56 | * perf_error__register - Register error logging functions |
| 68 | * @eops: The pointer to error logging function struct | 57 | * @eops: The pointer to error logging function struct |
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 6aa34e5afdcf..055fef34b6f6 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN | |||
| @@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)') | |||
| 26 | 26 | ||
| 27 | if test -r $GVF | 27 | if test -r $GVF |
| 28 | then | 28 | then |
| 29 | VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) | 29 | VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF) |
| 30 | else | 30 | else |
| 31 | VC=unset | 31 | VC=unset |
| 32 | fi | 32 | fi |
| 33 | test "$VN" = "$VC" || { | 33 | test "$VN" = "$VC" || { |
| 34 | echo >&2 "PERF_VERSION = $VN" | 34 | echo >&2 "PERF_VERSION = $VN" |
| 35 | echo "PERF_VERSION = $VN" >$GVF | 35 | echo "#define PERF_VERSION \"$VN\"" >$GVF |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | 38 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 6e2667fb8211..efbd98805ad0 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
| @@ -16,6 +16,5 @@ void trace_event(union perf_event *event); | |||
| 16 | 16 | ||
| 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
| 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
| 19 | int ui__error_paranoid(void); | ||
| 20 | 19 | ||
| 21 | #endif /* __PERF_DEBUG_H */ | 20 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7a2a3dc3ff03..e45332d08a58 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -22,6 +22,11 @@ | |||
| 22 | #include <linux/perf_event.h> | 22 | #include <linux/perf_event.h> |
| 23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
| 24 | 24 | ||
| 25 | static struct { | ||
| 26 | bool sample_id_all; | ||
| 27 | bool exclude_guest; | ||
| 28 | } perf_missing_features; | ||
| 29 | |||
| 25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 30 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
| 26 | 31 | ||
| 27 | static int __perf_evsel__sample_size(u64 sample_type) | 32 | static int __perf_evsel__sample_size(u64 sample_type) |
| @@ -463,7 +468,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
| 463 | struct perf_event_attr *attr = &evsel->attr; | 468 | struct perf_event_attr *attr = &evsel->attr; |
| 464 | int track = !evsel->idx; /* only the first counter needs these */ | 469 | int track = !evsel->idx; /* only the first counter needs these */ |
| 465 | 470 | ||
| 466 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | 471 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
| 467 | attr->inherit = !opts->no_inherit; | 472 | attr->inherit = !opts->no_inherit; |
| 468 | 473 | ||
| 469 | perf_evsel__set_sample_bit(evsel, IP); | 474 | perf_evsel__set_sample_bit(evsel, IP); |
| @@ -513,7 +518,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
| 513 | if (opts->period) | 518 | if (opts->period) |
| 514 | perf_evsel__set_sample_bit(evsel, PERIOD); | 519 | perf_evsel__set_sample_bit(evsel, PERIOD); |
| 515 | 520 | ||
| 516 | if (!opts->sample_id_all_missing && | 521 | if (!perf_missing_features.sample_id_all && |
| 517 | (opts->sample_time || !opts->no_inherit || | 522 | (opts->sample_time || !opts->no_inherit || |
| 518 | perf_target__has_cpu(&opts->target))) | 523 | perf_target__has_cpu(&opts->target))) |
| 519 | perf_evsel__set_sample_bit(evsel, TIME); | 524 | perf_evsel__set_sample_bit(evsel, TIME); |
| @@ -761,6 +766,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
| 761 | pid = evsel->cgrp->fd; | 766 | pid = evsel->cgrp->fd; |
| 762 | } | 767 | } |
| 763 | 768 | ||
| 769 | fallback_missing_features: | ||
| 770 | if (perf_missing_features.exclude_guest) | ||
| 771 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | ||
| 772 | retry_sample_id: | ||
| 773 | if (perf_missing_features.sample_id_all) | ||
| 774 | evsel->attr.sample_id_all = 0; | ||
| 775 | |||
| 764 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 776 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
| 765 | 777 | ||
| 766 | for (thread = 0; thread < threads->nr; thread++) { | 778 | for (thread = 0; thread < threads->nr; thread++) { |
| @@ -777,13 +789,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
| 777 | group_fd, flags); | 789 | group_fd, flags); |
| 778 | if (FD(evsel, cpu, thread) < 0) { | 790 | if (FD(evsel, cpu, thread) < 0) { |
| 779 | err = -errno; | 791 | err = -errno; |
| 780 | goto out_close; | 792 | goto try_fallback; |
| 781 | } | 793 | } |
| 782 | } | 794 | } |
| 783 | } | 795 | } |
| 784 | 796 | ||
| 785 | return 0; | 797 | return 0; |
| 786 | 798 | ||
| 799 | try_fallback: | ||
| 800 | if (err != -EINVAL || cpu > 0 || thread > 0) | ||
| 801 | goto out_close; | ||
| 802 | |||
| 803 | if (!perf_missing_features.exclude_guest && | ||
| 804 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | ||
| 805 | perf_missing_features.exclude_guest = true; | ||
| 806 | goto fallback_missing_features; | ||
| 807 | } else if (!perf_missing_features.sample_id_all) { | ||
| 808 | perf_missing_features.sample_id_all = true; | ||
| 809 | goto retry_sample_id; | ||
| 810 | } | ||
| 811 | |||
| 787 | out_close: | 812 | out_close: |
| 788 | do { | 813 | do { |
| 789 | while (--thread >= 0) { | 814 | while (--thread >= 0) { |
| @@ -1353,3 +1378,80 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
| 1353 | fputc('\n', fp); | 1378 | fputc('\n', fp); |
| 1354 | return ++printed; | 1379 | return ++printed; |
| 1355 | } | 1380 | } |
| 1381 | |||
| 1382 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | ||
| 1383 | char *msg, size_t msgsize) | ||
| 1384 | { | ||
| 1385 | if ((err == ENOENT || err == ENXIO) && | ||
| 1386 | evsel->attr.type == PERF_TYPE_HARDWARE && | ||
| 1387 | evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { | ||
| 1388 | /* | ||
| 1389 | * If it's cycles then fall back to hrtimer based | ||
| 1390 | * cpu-clock-tick sw counter, which is always available even if | ||
| 1391 | * no PMU support. | ||
| 1392 | * | ||
| 1393 | * PPC returns ENXIO until 2.6.37 (behavior changed with commit | ||
| 1394 | * b0a873e). | ||
| 1395 | */ | ||
| 1396 | scnprintf(msg, msgsize, "%s", | ||
| 1397 | "The cycles event is not supported, trying to fall back to cpu-clock-ticks"); | ||
| 1398 | |||
| 1399 | evsel->attr.type = PERF_TYPE_SOFTWARE; | ||
| 1400 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; | ||
| 1401 | |||
| 1402 | free(evsel->name); | ||
| 1403 | evsel->name = NULL; | ||
| 1404 | return true; | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | return false; | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | int perf_evsel__open_strerror(struct perf_evsel *evsel, | ||
| 1411 | struct perf_target *target, | ||
| 1412 | int err, char *msg, size_t size) | ||
| 1413 | { | ||
| 1414 | switch (err) { | ||
| 1415 | case EPERM: | ||
| 1416 | case EACCES: | ||
| 1417 | return scnprintf(msg, size, "%s", | ||
| 1418 | "You may not have permission to collect %sstats.\n" | ||
| 1419 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
| 1420 | " -1 - Not paranoid at all\n" | ||
| 1421 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
| 1422 | " 1 - Disallow cpu events for unpriv\n" | ||
| 1423 | " 2 - Disallow kernel profiling for unpriv", | ||
| 1424 | target->system_wide ? "system-wide " : ""); | ||
| 1425 | case ENOENT: | ||
| 1426 | return scnprintf(msg, size, "The %s event is not supported.", | ||
| 1427 | perf_evsel__name(evsel)); | ||
| 1428 | case EMFILE: | ||
| 1429 | return scnprintf(msg, size, "%s", | ||
| 1430 | "Too many events are opened.\n" | ||
| 1431 | "Try again after reducing the number of events."); | ||
| 1432 | case ENODEV: | ||
| 1433 | if (target->cpu_list) | ||
| 1434 | return scnprintf(msg, size, "%s", | ||
| 1435 | "No such device - did you specify an out-of-range profile CPU?\n"); | ||
| 1436 | break; | ||
| 1437 | case EOPNOTSUPP: | ||
| 1438 | if (evsel->attr.precise_ip) | ||
| 1439 | return scnprintf(msg, size, "%s", | ||
| 1440 | "\'precise\' request may not be supported. Try removing 'p' modifier."); | ||
| 1441 | #if defined(__i386__) || defined(__x86_64__) | ||
| 1442 | if (evsel->attr.type == PERF_TYPE_HARDWARE) | ||
| 1443 | return scnprintf(msg, size, "%s", | ||
| 1444 | "No hardware sampling interrupt available.\n" | ||
| 1445 | "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); | ||
| 1446 | #endif | ||
| 1447 | break; | ||
| 1448 | default: | ||
| 1449 | break; | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | return scnprintf(msg, size, | ||
| 1453 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" | ||
| 1454 | "/bin/dmesg may provide additional information.\n" | ||
| 1455 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", | ||
| 1456 | err, strerror(err), perf_evsel__name(evsel)); | ||
| 1457 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 9cb8a0215711..c68d1b82e843 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -251,4 +251,10 @@ struct perf_attr_details { | |||
| 251 | 251 | ||
| 252 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 252 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
| 253 | struct perf_attr_details *details, FILE *fp); | 253 | struct perf_attr_details *details, FILE *fp); |
| 254 | |||
| 255 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | ||
| 256 | char *msg, size_t msgsize); | ||
| 257 | int perf_evsel__open_strerror(struct perf_evsel *evsel, | ||
| 258 | struct perf_target *target, | ||
| 259 | int err, char *msg, size_t size); | ||
| 254 | #endif /* __PERF_EVSEL_H */ | 260 | #endif /* __PERF_EVSEL_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b7da4634a047..fccd69dbbbb9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph) | |||
| 148 | u32 len; | 148 | u32 len; |
| 149 | char *buf; | 149 | char *buf; |
| 150 | 150 | ||
| 151 | sz = read(fd, &len, sizeof(len)); | 151 | sz = readn(fd, &len, sizeof(len)); |
| 152 | if (sz < (ssize_t)sizeof(len)) | 152 | if (sz < (ssize_t)sizeof(len)) |
| 153 | return NULL; | 153 | return NULL; |
| 154 | 154 | ||
| @@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph) | |||
| 159 | if (!buf) | 159 | if (!buf) |
| 160 | return NULL; | 160 | return NULL; |
| 161 | 161 | ||
| 162 | ret = read(fd, buf, len); | 162 | ret = readn(fd, buf, len); |
| 163 | if (ret == (ssize_t)len) { | 163 | if (ret == (ssize_t)len) { |
| 164 | /* | 164 | /* |
| 165 | * strings are padded by zeroes | 165 | * strings are padded by zeroes |
| @@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd) | |||
| 287 | struct perf_session *session = container_of(header, | 287 | struct perf_session *session = container_of(header, |
| 288 | struct perf_session, header); | 288 | struct perf_session, header); |
| 289 | struct rb_node *nd; | 289 | struct rb_node *nd; |
| 290 | int err = machine__write_buildid_table(&session->host_machine, fd); | 290 | int err = machine__write_buildid_table(&session->machines.host, fd); |
| 291 | 291 | ||
| 292 | if (err) | 292 | if (err) |
| 293 | return err; | 293 | return err; |
| 294 | 294 | ||
| 295 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 295 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
| 296 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 296 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 297 | err = machine__write_buildid_table(pos, fd); | 297 | err = machine__write_buildid_table(pos, fd); |
| 298 | if (err) | 298 | if (err) |
| @@ -448,9 +448,9 @@ static int perf_session__cache_build_ids(struct perf_session *session) | |||
| 448 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 448 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
| 449 | return -1; | 449 | return -1; |
| 450 | 450 | ||
| 451 | ret = machine__cache_build_ids(&session->host_machine, debugdir); | 451 | ret = machine__cache_build_ids(&session->machines.host, debugdir); |
| 452 | 452 | ||
| 453 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 453 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
| 454 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 454 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 455 | ret |= machine__cache_build_ids(pos, debugdir); | 455 | ret |= machine__cache_build_ids(pos, debugdir); |
| 456 | } | 456 | } |
| @@ -467,9 +467,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits) | |||
| 467 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) | 467 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) |
| 468 | { | 468 | { |
| 469 | struct rb_node *nd; | 469 | struct rb_node *nd; |
| 470 | bool ret = machine__read_build_ids(&session->host_machine, with_hits); | 470 | bool ret = machine__read_build_ids(&session->machines.host, with_hits); |
| 471 | 471 | ||
| 472 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 472 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
| 473 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 473 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 474 | ret |= machine__read_build_ids(pos, with_hits); | 474 | ret |= machine__read_build_ids(pos, with_hits); |
| 475 | } | 475 | } |
| @@ -1051,16 +1051,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, | |||
| 1051 | struct perf_pmu *pmu = NULL; | 1051 | struct perf_pmu *pmu = NULL; |
| 1052 | off_t offset = lseek(fd, 0, SEEK_CUR); | 1052 | off_t offset = lseek(fd, 0, SEEK_CUR); |
| 1053 | __u32 pmu_num = 0; | 1053 | __u32 pmu_num = 0; |
| 1054 | int ret; | ||
| 1054 | 1055 | ||
| 1055 | /* write real pmu_num later */ | 1056 | /* write real pmu_num later */ |
| 1056 | do_write(fd, &pmu_num, sizeof(pmu_num)); | 1057 | ret = do_write(fd, &pmu_num, sizeof(pmu_num)); |
| 1058 | if (ret < 0) | ||
| 1059 | return ret; | ||
| 1057 | 1060 | ||
| 1058 | while ((pmu = perf_pmu__scan(pmu))) { | 1061 | while ((pmu = perf_pmu__scan(pmu))) { |
| 1059 | if (!pmu->name) | 1062 | if (!pmu->name) |
| 1060 | continue; | 1063 | continue; |
| 1061 | pmu_num++; | 1064 | pmu_num++; |
| 1062 | do_write(fd, &pmu->type, sizeof(pmu->type)); | 1065 | |
| 1063 | do_write_string(fd, pmu->name); | 1066 | ret = do_write(fd, &pmu->type, sizeof(pmu->type)); |
| 1067 | if (ret < 0) | ||
| 1068 | return ret; | ||
| 1069 | |||
| 1070 | ret = do_write_string(fd, pmu->name); | ||
| 1071 | if (ret < 0) | ||
| 1072 | return ret; | ||
| 1064 | } | 1073 | } |
| 1065 | 1074 | ||
| 1066 | if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { | 1075 | if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { |
| @@ -1209,14 +1218,14 @@ read_event_desc(struct perf_header *ph, int fd) | |||
| 1209 | size_t msz; | 1218 | size_t msz; |
| 1210 | 1219 | ||
| 1211 | /* number of events */ | 1220 | /* number of events */ |
| 1212 | ret = read(fd, &nre, sizeof(nre)); | 1221 | ret = readn(fd, &nre, sizeof(nre)); |
| 1213 | if (ret != (ssize_t)sizeof(nre)) | 1222 | if (ret != (ssize_t)sizeof(nre)) |
| 1214 | goto error; | 1223 | goto error; |
| 1215 | 1224 | ||
| 1216 | if (ph->needs_swap) | 1225 | if (ph->needs_swap) |
| 1217 | nre = bswap_32(nre); | 1226 | nre = bswap_32(nre); |
| 1218 | 1227 | ||
| 1219 | ret = read(fd, &sz, sizeof(sz)); | 1228 | ret = readn(fd, &sz, sizeof(sz)); |
| 1220 | if (ret != (ssize_t)sizeof(sz)) | 1229 | if (ret != (ssize_t)sizeof(sz)) |
| 1221 | goto error; | 1230 | goto error; |
| 1222 | 1231 | ||
| @@ -1244,7 +1253,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
| 1244 | * must read entire on-file attr struct to | 1253 | * must read entire on-file attr struct to |
| 1245 | * sync up with layout. | 1254 | * sync up with layout. |
| 1246 | */ | 1255 | */ |
| 1247 | ret = read(fd, buf, sz); | 1256 | ret = readn(fd, buf, sz); |
| 1248 | if (ret != (ssize_t)sz) | 1257 | if (ret != (ssize_t)sz) |
| 1249 | goto error; | 1258 | goto error; |
| 1250 | 1259 | ||
| @@ -1253,7 +1262,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
| 1253 | 1262 | ||
| 1254 | memcpy(&evsel->attr, buf, msz); | 1263 | memcpy(&evsel->attr, buf, msz); |
| 1255 | 1264 | ||
| 1256 | ret = read(fd, &nr, sizeof(nr)); | 1265 | ret = readn(fd, &nr, sizeof(nr)); |
| 1257 | if (ret != (ssize_t)sizeof(nr)) | 1266 | if (ret != (ssize_t)sizeof(nr)) |
| 1258 | goto error; | 1267 | goto error; |
| 1259 | 1268 | ||
| @@ -1274,7 +1283,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
| 1274 | evsel->id = id; | 1283 | evsel->id = id; |
| 1275 | 1284 | ||
| 1276 | for (j = 0 ; j < nr; j++) { | 1285 | for (j = 0 ; j < nr; j++) { |
| 1277 | ret = read(fd, id, sizeof(*id)); | 1286 | ret = readn(fd, id, sizeof(*id)); |
| 1278 | if (ret != (ssize_t)sizeof(*id)) | 1287 | if (ret != (ssize_t)sizeof(*id)) |
| 1279 | goto error; | 1288 | goto error; |
| 1280 | if (ph->needs_swap) | 1289 | if (ph->needs_swap) |
| @@ -1506,14 +1515,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
| 1506 | while (offset < limit) { | 1515 | while (offset < limit) { |
| 1507 | ssize_t len; | 1516 | ssize_t len; |
| 1508 | 1517 | ||
| 1509 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | 1518 | if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) |
| 1510 | return -1; | 1519 | return -1; |
| 1511 | 1520 | ||
| 1512 | if (header->needs_swap) | 1521 | if (header->needs_swap) |
| 1513 | perf_event_header__bswap(&old_bev.header); | 1522 | perf_event_header__bswap(&old_bev.header); |
| 1514 | 1523 | ||
| 1515 | len = old_bev.header.size - sizeof(old_bev); | 1524 | len = old_bev.header.size - sizeof(old_bev); |
| 1516 | if (read(input, filename, len) != len) | 1525 | if (readn(input, filename, len) != len) |
| 1517 | return -1; | 1526 | return -1; |
| 1518 | 1527 | ||
| 1519 | bev.header = old_bev.header; | 1528 | bev.header = old_bev.header; |
| @@ -1548,14 +1557,14 @@ static int perf_header__read_build_ids(struct perf_header *header, | |||
| 1548 | while (offset < limit) { | 1557 | while (offset < limit) { |
| 1549 | ssize_t len; | 1558 | ssize_t len; |
| 1550 | 1559 | ||
| 1551 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 1560 | if (readn(input, &bev, sizeof(bev)) != sizeof(bev)) |
| 1552 | goto out; | 1561 | goto out; |
| 1553 | 1562 | ||
| 1554 | if (header->needs_swap) | 1563 | if (header->needs_swap) |
| 1555 | perf_event_header__bswap(&bev.header); | 1564 | perf_event_header__bswap(&bev.header); |
| 1556 | 1565 | ||
| 1557 | len = bev.header.size - sizeof(bev); | 1566 | len = bev.header.size - sizeof(bev); |
| 1558 | if (read(input, filename, len) != len) | 1567 | if (readn(input, filename, len) != len) |
| 1559 | goto out; | 1568 | goto out; |
| 1560 | /* | 1569 | /* |
| 1561 | * The a1645ce1 changeset: | 1570 | * The a1645ce1 changeset: |
| @@ -1641,7 +1650,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
| 1641 | size_t ret; | 1650 | size_t ret; |
| 1642 | u32 nr; | 1651 | u32 nr; |
| 1643 | 1652 | ||
| 1644 | ret = read(fd, &nr, sizeof(nr)); | 1653 | ret = readn(fd, &nr, sizeof(nr)); |
| 1645 | if (ret != sizeof(nr)) | 1654 | if (ret != sizeof(nr)) |
| 1646 | return -1; | 1655 | return -1; |
| 1647 | 1656 | ||
| @@ -1650,7 +1659,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
| 1650 | 1659 | ||
| 1651 | ph->env.nr_cpus_online = nr; | 1660 | ph->env.nr_cpus_online = nr; |
| 1652 | 1661 | ||
| 1653 | ret = read(fd, &nr, sizeof(nr)); | 1662 | ret = readn(fd, &nr, sizeof(nr)); |
| 1654 | if (ret != sizeof(nr)) | 1663 | if (ret != sizeof(nr)) |
| 1655 | return -1; | 1664 | return -1; |
| 1656 | 1665 | ||
| @@ -1684,7 +1693,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, | |||
| 1684 | uint64_t mem; | 1693 | uint64_t mem; |
| 1685 | size_t ret; | 1694 | size_t ret; |
| 1686 | 1695 | ||
| 1687 | ret = read(fd, &mem, sizeof(mem)); | 1696 | ret = readn(fd, &mem, sizeof(mem)); |
| 1688 | if (ret != sizeof(mem)) | 1697 | if (ret != sizeof(mem)) |
| 1689 | return -1; | 1698 | return -1; |
| 1690 | 1699 | ||
| @@ -1756,7 +1765,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, | |||
| 1756 | u32 nr, i; | 1765 | u32 nr, i; |
| 1757 | struct strbuf sb; | 1766 | struct strbuf sb; |
| 1758 | 1767 | ||
| 1759 | ret = read(fd, &nr, sizeof(nr)); | 1768 | ret = readn(fd, &nr, sizeof(nr)); |
| 1760 | if (ret != sizeof(nr)) | 1769 | if (ret != sizeof(nr)) |
| 1761 | return -1; | 1770 | return -1; |
| 1762 | 1771 | ||
| @@ -1792,7 +1801,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
| 1792 | char *str; | 1801 | char *str; |
| 1793 | struct strbuf sb; | 1802 | struct strbuf sb; |
| 1794 | 1803 | ||
| 1795 | ret = read(fd, &nr, sizeof(nr)); | 1804 | ret = readn(fd, &nr, sizeof(nr)); |
| 1796 | if (ret != sizeof(nr)) | 1805 | if (ret != sizeof(nr)) |
| 1797 | return -1; | 1806 | return -1; |
| 1798 | 1807 | ||
| @@ -1813,7 +1822,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
| 1813 | } | 1822 | } |
| 1814 | ph->env.sibling_cores = strbuf_detach(&sb, NULL); | 1823 | ph->env.sibling_cores = strbuf_detach(&sb, NULL); |
| 1815 | 1824 | ||
| 1816 | ret = read(fd, &nr, sizeof(nr)); | 1825 | ret = readn(fd, &nr, sizeof(nr)); |
| 1817 | if (ret != sizeof(nr)) | 1826 | if (ret != sizeof(nr)) |
| 1818 | return -1; | 1827 | return -1; |
| 1819 | 1828 | ||
| @@ -1850,7 +1859,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
| 1850 | struct strbuf sb; | 1859 | struct strbuf sb; |
| 1851 | 1860 | ||
| 1852 | /* nr nodes */ | 1861 | /* nr nodes */ |
| 1853 | ret = read(fd, &nr, sizeof(nr)); | 1862 | ret = readn(fd, &nr, sizeof(nr)); |
| 1854 | if (ret != sizeof(nr)) | 1863 | if (ret != sizeof(nr)) |
| 1855 | goto error; | 1864 | goto error; |
| 1856 | 1865 | ||
| @@ -1862,15 +1871,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
| 1862 | 1871 | ||
| 1863 | for (i = 0; i < nr; i++) { | 1872 | for (i = 0; i < nr; i++) { |
| 1864 | /* node number */ | 1873 | /* node number */ |
| 1865 | ret = read(fd, &node, sizeof(node)); | 1874 | ret = readn(fd, &node, sizeof(node)); |
| 1866 | if (ret != sizeof(node)) | 1875 | if (ret != sizeof(node)) |
| 1867 | goto error; | 1876 | goto error; |
| 1868 | 1877 | ||
| 1869 | ret = read(fd, &mem_total, sizeof(u64)); | 1878 | ret = readn(fd, &mem_total, sizeof(u64)); |
| 1870 | if (ret != sizeof(u64)) | 1879 | if (ret != sizeof(u64)) |
| 1871 | goto error; | 1880 | goto error; |
| 1872 | 1881 | ||
| 1873 | ret = read(fd, &mem_free, sizeof(u64)); | 1882 | ret = readn(fd, &mem_free, sizeof(u64)); |
| 1874 | if (ret != sizeof(u64)) | 1883 | if (ret != sizeof(u64)) |
| 1875 | goto error; | 1884 | goto error; |
| 1876 | 1885 | ||
| @@ -1909,7 +1918,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
| 1909 | u32 type; | 1918 | u32 type; |
| 1910 | struct strbuf sb; | 1919 | struct strbuf sb; |
| 1911 | 1920 | ||
| 1912 | ret = read(fd, &pmu_num, sizeof(pmu_num)); | 1921 | ret = readn(fd, &pmu_num, sizeof(pmu_num)); |
| 1913 | if (ret != sizeof(pmu_num)) | 1922 | if (ret != sizeof(pmu_num)) |
| 1914 | return -1; | 1923 | return -1; |
| 1915 | 1924 | ||
| @@ -1925,7 +1934,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
| 1925 | strbuf_init(&sb, 128); | 1934 | strbuf_init(&sb, 128); |
| 1926 | 1935 | ||
| 1927 | while (pmu_num) { | 1936 | while (pmu_num) { |
| 1928 | if (read(fd, &type, sizeof(type)) != sizeof(type)) | 1937 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) |
| 1929 | goto error; | 1938 | goto error; |
| 1930 | if (ph->needs_swap) | 1939 | if (ph->needs_swap) |
| 1931 | type = bswap_32(type); | 1940 | type = bswap_32(type); |
| @@ -2912,7 +2921,7 @@ int perf_event__process_tracing_data(union perf_event *event, | |||
| 2912 | session->repipe); | 2921 | session->repipe); |
| 2913 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; | 2922 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; |
| 2914 | 2923 | ||
| 2915 | if (read(session->fd, buf, padding) < 0) | 2924 | if (readn(session->fd, buf, padding) < 0) |
| 2916 | die("reading input file"); | 2925 | die("reading input file"); |
| 2917 | if (session->repipe) { | 2926 | if (session->repipe) { |
| 2918 | int retw = write(STDOUT_FILENO, buf, padding); | 2927 | int retw = write(STDOUT_FILENO, buf, padding); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 82df1b26f0d4..8170a3d11ffa 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -82,6 +82,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
| 82 | hists__new_col_len(hists, HISTC_DSO, len); | 82 | hists__new_col_len(hists, HISTC_DSO, len); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | if (h->parent) | ||
| 86 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); | ||
| 87 | |||
| 85 | if (h->branch_info) { | 88 | if (h->branch_info) { |
| 86 | int symlen; | 89 | int symlen; |
| 87 | /* | 90 | /* |
| @@ -242,6 +245,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
| 242 | 245 | ||
| 243 | if (he->ms.map) | 246 | if (he->ms.map) |
| 244 | he->ms.map->referenced = true; | 247 | he->ms.map->referenced = true; |
| 248 | |||
| 249 | if (he->branch_info) { | ||
| 250 | if (he->branch_info->from.map) | ||
| 251 | he->branch_info->from.map->referenced = true; | ||
| 252 | if (he->branch_info->to.map) | ||
| 253 | he->branch_info->to.map->referenced = true; | ||
| 254 | } | ||
| 255 | |||
| 245 | if (symbol_conf.use_callchain) | 256 | if (symbol_conf.use_callchain) |
| 246 | callchain_init(he->callchain); | 257 | callchain_init(he->callchain); |
| 247 | 258 | ||
| @@ -251,7 +262,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
| 251 | return he; | 262 | return he; |
| 252 | } | 263 | } |
| 253 | 264 | ||
| 254 | static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) | 265 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) |
| 255 | { | 266 | { |
| 256 | if (!h->filtered) { | 267 | if (!h->filtered) { |
| 257 | hists__calc_col_len(hists, h); | 268 | hists__calc_col_len(hists, h); |
| @@ -285,7 +296,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
| 285 | parent = *p; | 296 | parent = *p; |
| 286 | he = rb_entry(parent, struct hist_entry, rb_node_in); | 297 | he = rb_entry(parent, struct hist_entry, rb_node_in); |
| 287 | 298 | ||
| 288 | cmp = hist_entry__cmp(entry, he); | 299 | /* |
| 300 | * Make sure that it receives arguments in a same order as | ||
| 301 | * hist_entry__collapse() so that we can use an appropriate | ||
| 302 | * function when searching an entry regardless which sort | ||
| 303 | * keys were used. | ||
| 304 | */ | ||
| 305 | cmp = hist_entry__cmp(he, entry); | ||
| 289 | 306 | ||
| 290 | if (!cmp) { | 307 | if (!cmp) { |
| 291 | he_stat__add_period(&he->stat, period); | 308 | he_stat__add_period(&he->stat, period); |
| @@ -711,25 +728,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) | |||
| 711 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | 728 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); |
| 712 | } | 729 | } |
| 713 | 730 | ||
| 731 | void events_stats__inc(struct events_stats *stats, u32 type) | ||
| 732 | { | ||
| 733 | ++stats->nr_events[0]; | ||
| 734 | ++stats->nr_events[type]; | ||
| 735 | } | ||
| 736 | |||
| 714 | void hists__inc_nr_events(struct hists *hists, u32 type) | 737 | void hists__inc_nr_events(struct hists *hists, u32 type) |
| 715 | { | 738 | { |
| 716 | ++hists->stats.nr_events[0]; | 739 | events_stats__inc(&hists->stats, type); |
| 717 | ++hists->stats.nr_events[type]; | ||
| 718 | } | 740 | } |
| 719 | 741 | ||
| 720 | static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | 742 | static struct hist_entry *hists__add_dummy_entry(struct hists *hists, |
| 721 | struct hist_entry *pair) | 743 | struct hist_entry *pair) |
| 722 | { | 744 | { |
| 723 | struct rb_node **p = &hists->entries.rb_node; | 745 | struct rb_root *root; |
| 746 | struct rb_node **p; | ||
| 724 | struct rb_node *parent = NULL; | 747 | struct rb_node *parent = NULL; |
| 725 | struct hist_entry *he; | 748 | struct hist_entry *he; |
| 726 | int cmp; | 749 | int cmp; |
| 727 | 750 | ||
| 751 | if (sort__need_collapse) | ||
| 752 | root = &hists->entries_collapsed; | ||
| 753 | else | ||
| 754 | root = hists->entries_in; | ||
| 755 | |||
| 756 | p = &root->rb_node; | ||
| 757 | |||
| 728 | while (*p != NULL) { | 758 | while (*p != NULL) { |
| 729 | parent = *p; | 759 | parent = *p; |
| 730 | he = rb_entry(parent, struct hist_entry, rb_node); | 760 | he = rb_entry(parent, struct hist_entry, rb_node_in); |
| 731 | 761 | ||
| 732 | cmp = hist_entry__cmp(pair, he); | 762 | cmp = hist_entry__collapse(he, pair); |
| 733 | 763 | ||
| 734 | if (!cmp) | 764 | if (!cmp) |
| 735 | goto out; | 765 | goto out; |
| @@ -744,8 +774,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
| 744 | if (he) { | 774 | if (he) { |
| 745 | memset(&he->stat, 0, sizeof(he->stat)); | 775 | memset(&he->stat, 0, sizeof(he->stat)); |
| 746 | he->hists = hists; | 776 | he->hists = hists; |
| 747 | rb_link_node(&he->rb_node, parent, p); | 777 | rb_link_node(&he->rb_node_in, parent, p); |
| 748 | rb_insert_color(&he->rb_node, &hists->entries); | 778 | rb_insert_color(&he->rb_node_in, root); |
| 749 | hists__inc_nr_entries(hists, he); | 779 | hists__inc_nr_entries(hists, he); |
| 750 | } | 780 | } |
| 751 | out: | 781 | out: |
| @@ -755,11 +785,16 @@ out: | |||
| 755 | static struct hist_entry *hists__find_entry(struct hists *hists, | 785 | static struct hist_entry *hists__find_entry(struct hists *hists, |
| 756 | struct hist_entry *he) | 786 | struct hist_entry *he) |
| 757 | { | 787 | { |
| 758 | struct rb_node *n = hists->entries.rb_node; | 788 | struct rb_node *n; |
| 789 | |||
| 790 | if (sort__need_collapse) | ||
| 791 | n = hists->entries_collapsed.rb_node; | ||
| 792 | else | ||
| 793 | n = hists->entries_in->rb_node; | ||
| 759 | 794 | ||
| 760 | while (n) { | 795 | while (n) { |
| 761 | struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); | 796 | struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in); |
| 762 | int64_t cmp = hist_entry__cmp(he, iter); | 797 | int64_t cmp = hist_entry__collapse(iter, he); |
| 763 | 798 | ||
| 764 | if (cmp < 0) | 799 | if (cmp < 0) |
| 765 | n = n->rb_left; | 800 | n = n->rb_left; |
| @@ -777,11 +812,17 @@ static struct hist_entry *hists__find_entry(struct hists *hists, | |||
| 777 | */ | 812 | */ |
| 778 | void hists__match(struct hists *leader, struct hists *other) | 813 | void hists__match(struct hists *leader, struct hists *other) |
| 779 | { | 814 | { |
| 815 | struct rb_root *root; | ||
| 780 | struct rb_node *nd; | 816 | struct rb_node *nd; |
| 781 | struct hist_entry *pos, *pair; | 817 | struct hist_entry *pos, *pair; |
| 782 | 818 | ||
| 783 | for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { | 819 | if (sort__need_collapse) |
| 784 | pos = rb_entry(nd, struct hist_entry, rb_node); | 820 | root = &leader->entries_collapsed; |
| 821 | else | ||
| 822 | root = leader->entries_in; | ||
| 823 | |||
| 824 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
| 825 | pos = rb_entry(nd, struct hist_entry, rb_node_in); | ||
| 785 | pair = hists__find_entry(other, pos); | 826 | pair = hists__find_entry(other, pos); |
| 786 | 827 | ||
| 787 | if (pair) | 828 | if (pair) |
| @@ -796,11 +837,17 @@ void hists__match(struct hists *leader, struct hists *other) | |||
| 796 | */ | 837 | */ |
| 797 | int hists__link(struct hists *leader, struct hists *other) | 838 | int hists__link(struct hists *leader, struct hists *other) |
| 798 | { | 839 | { |
| 840 | struct rb_root *root; | ||
| 799 | struct rb_node *nd; | 841 | struct rb_node *nd; |
| 800 | struct hist_entry *pos, *pair; | 842 | struct hist_entry *pos, *pair; |
| 801 | 843 | ||
| 802 | for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { | 844 | if (sort__need_collapse) |
| 803 | pos = rb_entry(nd, struct hist_entry, rb_node); | 845 | root = &other->entries_collapsed; |
| 846 | else | ||
| 847 | root = other->entries_in; | ||
| 848 | |||
| 849 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
| 850 | pos = rb_entry(nd, struct hist_entry, rb_node_in); | ||
| 804 | 851 | ||
| 805 | if (!hist_entry__has_pairs(pos)) { | 852 | if (!hist_entry__has_pairs(pos)) { |
| 806 | pair = hists__add_dummy_entry(leader, pos); | 853 | pair = hists__add_dummy_entry(leader, pos); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 5b3b0075be64..38624686ee9a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user, | |||
| 96 | bool zap_kernel); | 96 | bool zap_kernel); |
| 97 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | 97 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
| 98 | 98 | ||
| 99 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); | ||
| 99 | void hists__inc_nr_events(struct hists *self, u32 type); | 100 | void hists__inc_nr_events(struct hists *self, u32 type); |
| 100 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 101 | void events_stats__inc(struct events_stats *stats, u32 type); |
| 102 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | ||
| 101 | 103 | ||
| 102 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, | 104 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, |
| 103 | int max_cols, FILE *fp); | 105 | int max_cols, FILE *fp); |
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index a55d8cf083c9..45cf10a562bd 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 14 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
| 15 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) | 15 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) |
| 16 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) | 16 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) |
| 17 | #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) | ||
| 17 | 18 | ||
| 18 | #define for_each_set_bit(bit, addr, size) \ | 19 | #define for_each_set_bit(bit, addr, size) \ |
| 19 | for ((bit) = find_first_bit((addr), (size)); \ | 20 | for ((bit) = find_first_bit((addr), (size)); \ |
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c index 9d0740024ba8..11a8d86f7fea 100644 --- a/tools/perf/util/intlist.c +++ b/tools/perf/util/intlist.c | |||
| @@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node) | |||
| 59 | 59 | ||
| 60 | struct int_node *intlist__find(struct intlist *ilist, int i) | 60 | struct int_node *intlist__find(struct intlist *ilist, int i) |
| 61 | { | 61 | { |
| 62 | struct int_node *node = NULL; | 62 | struct int_node *node; |
| 63 | struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); | 63 | struct rb_node *rb_node; |
| 64 | 64 | ||
| 65 | if (ilist == NULL) | ||
| 66 | return NULL; | ||
| 67 | |||
| 68 | node = NULL; | ||
| 69 | rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); | ||
| 65 | if (rb_node) | 70 | if (rb_node) |
| 66 | node = container_of(rb_node, struct int_node, rb_node); | 71 | node = container_of(rb_node, struct int_node, rb_node); |
| 67 | 72 | ||
| 68 | return node; | 73 | return node; |
| 69 | } | 74 | } |
| 70 | 75 | ||
| 71 | struct intlist *intlist__new(void) | 76 | static int intlist__parse_list(struct intlist *ilist, const char *s) |
| 77 | { | ||
| 78 | char *sep; | ||
| 79 | int err; | ||
| 80 | |||
| 81 | do { | ||
| 82 | long value = strtol(s, &sep, 10); | ||
| 83 | err = -EINVAL; | ||
| 84 | if (*sep != ',' && *sep != '\0') | ||
| 85 | break; | ||
| 86 | err = intlist__add(ilist, value); | ||
| 87 | if (err) | ||
| 88 | break; | ||
| 89 | s = sep + 1; | ||
| 90 | } while (*sep != '\0'); | ||
| 91 | |||
| 92 | return err; | ||
| 93 | } | ||
| 94 | |||
| 95 | struct intlist *intlist__new(const char *slist) | ||
| 72 | { | 96 | { |
| 73 | struct intlist *ilist = malloc(sizeof(*ilist)); | 97 | struct intlist *ilist = malloc(sizeof(*ilist)); |
| 74 | 98 | ||
| @@ -77,9 +101,15 @@ struct intlist *intlist__new(void) | |||
| 77 | ilist->rblist.node_cmp = intlist__node_cmp; | 101 | ilist->rblist.node_cmp = intlist__node_cmp; |
| 78 | ilist->rblist.node_new = intlist__node_new; | 102 | ilist->rblist.node_new = intlist__node_new; |
| 79 | ilist->rblist.node_delete = intlist__node_delete; | 103 | ilist->rblist.node_delete = intlist__node_delete; |
| 104 | |||
| 105 | if (slist && intlist__parse_list(ilist, slist)) | ||
| 106 | goto out_delete; | ||
| 80 | } | 107 | } |
| 81 | 108 | ||
| 82 | return ilist; | 109 | return ilist; |
| 110 | out_delete: | ||
| 111 | intlist__delete(ilist); | ||
| 112 | return NULL; | ||
| 83 | } | 113 | } |
| 84 | 114 | ||
| 85 | void intlist__delete(struct intlist *ilist) | 115 | void intlist__delete(struct intlist *ilist) |
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h index 6d63ab90db50..62351dad848f 100644 --- a/tools/perf/util/intlist.h +++ b/tools/perf/util/intlist.h | |||
| @@ -15,7 +15,7 @@ struct intlist { | |||
| 15 | struct rblist rblist; | 15 | struct rblist rblist; |
| 16 | }; | 16 | }; |
| 17 | 17 | ||
| 18 | struct intlist *intlist__new(void); | 18 | struct intlist *intlist__new(const char *slist); |
| 19 | void intlist__delete(struct intlist *ilist); | 19 | void intlist__delete(struct intlist *ilist); |
| 20 | 20 | ||
| 21 | void intlist__remove(struct intlist *ilist, struct int_node *in); | 21 | void intlist__remove(struct intlist *ilist, struct int_node *in); |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 71fa90391fe4..efdb38e65a92 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
| @@ -91,10 +91,22 @@ void machine__delete(struct machine *machine) | |||
| 91 | free(machine); | 91 | free(machine); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | 94 | void machines__init(struct machines *machines) |
| 95 | { | ||
| 96 | machine__init(&machines->host, "", HOST_KERNEL_ID); | ||
| 97 | machines->guests = RB_ROOT; | ||
| 98 | } | ||
| 99 | |||
| 100 | void machines__exit(struct machines *machines) | ||
| 101 | { | ||
| 102 | machine__exit(&machines->host); | ||
| 103 | /* XXX exit guest */ | ||
| 104 | } | ||
| 105 | |||
| 106 | struct machine *machines__add(struct machines *machines, pid_t pid, | ||
| 95 | const char *root_dir) | 107 | const char *root_dir) |
| 96 | { | 108 | { |
| 97 | struct rb_node **p = &machines->rb_node; | 109 | struct rb_node **p = &machines->guests.rb_node; |
| 98 | struct rb_node *parent = NULL; | 110 | struct rb_node *parent = NULL; |
| 99 | struct machine *pos, *machine = malloc(sizeof(*machine)); | 111 | struct machine *pos, *machine = malloc(sizeof(*machine)); |
| 100 | 112 | ||
| @@ -116,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid, | |||
| 116 | } | 128 | } |
| 117 | 129 | ||
| 118 | rb_link_node(&machine->rb_node, parent, p); | 130 | rb_link_node(&machine->rb_node, parent, p); |
| 119 | rb_insert_color(&machine->rb_node, machines); | 131 | rb_insert_color(&machine->rb_node, &machines->guests); |
| 120 | 132 | ||
| 121 | return machine; | 133 | return machine; |
| 122 | } | 134 | } |
| 123 | 135 | ||
| 124 | struct machine *machines__find(struct rb_root *machines, pid_t pid) | 136 | struct machine *machines__find(struct machines *machines, pid_t pid) |
| 125 | { | 137 | { |
| 126 | struct rb_node **p = &machines->rb_node; | 138 | struct rb_node **p = &machines->guests.rb_node; |
| 127 | struct rb_node *parent = NULL; | 139 | struct rb_node *parent = NULL; |
| 128 | struct machine *machine; | 140 | struct machine *machine; |
| 129 | struct machine *default_machine = NULL; | 141 | struct machine *default_machine = NULL; |
| 130 | 142 | ||
| 143 | if (pid == HOST_KERNEL_ID) | ||
| 144 | return &machines->host; | ||
| 145 | |||
| 131 | while (*p != NULL) { | 146 | while (*p != NULL) { |
| 132 | parent = *p; | 147 | parent = *p; |
| 133 | machine = rb_entry(parent, struct machine, rb_node); | 148 | machine = rb_entry(parent, struct machine, rb_node); |
| @@ -144,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid) | |||
| 144 | return default_machine; | 159 | return default_machine; |
| 145 | } | 160 | } |
| 146 | 161 | ||
| 147 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid) | 162 | struct machine *machines__findnew(struct machines *machines, pid_t pid) |
| 148 | { | 163 | { |
| 149 | char path[PATH_MAX]; | 164 | char path[PATH_MAX]; |
| 150 | const char *root_dir = ""; | 165 | const char *root_dir = ""; |
| @@ -178,12 +193,12 @@ out: | |||
| 178 | return machine; | 193 | return machine; |
| 179 | } | 194 | } |
| 180 | 195 | ||
| 181 | void machines__process(struct rb_root *machines, | 196 | void machines__process_guests(struct machines *machines, |
| 182 | machine__process_t process, void *data) | 197 | machine__process_t process, void *data) |
| 183 | { | 198 | { |
| 184 | struct rb_node *nd; | 199 | struct rb_node *nd; |
| 185 | 200 | ||
| 186 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | 201 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
| 187 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 202 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 188 | process(pos, data); | 203 | process(pos, data); |
| 189 | } | 204 | } |
| @@ -203,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size) | |||
| 203 | return bf; | 218 | return bf; |
| 204 | } | 219 | } |
| 205 | 220 | ||
| 206 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) | 221 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) |
| 207 | { | 222 | { |
| 208 | struct rb_node *node; | 223 | struct rb_node *node; |
| 209 | struct machine *machine; | 224 | struct machine *machine; |
| 210 | 225 | ||
| 211 | for (node = rb_first(machines); node; node = rb_next(node)) { | 226 | machines->host.id_hdr_size = id_hdr_size; |
| 227 | |||
| 228 | for (node = rb_first(&machines->guests); node; node = rb_next(node)) { | ||
| 212 | machine = rb_entry(node, struct machine, rb_node); | 229 | machine = rb_entry(node, struct machine, rb_node); |
| 213 | machine->id_hdr_size = id_hdr_size; | 230 | machine->id_hdr_size = id_hdr_size; |
| 214 | } | 231 | } |
| @@ -313,12 +330,13 @@ struct map *machine__new_module(struct machine *machine, u64 start, | |||
| 313 | return map; | 330 | return map; |
| 314 | } | 331 | } |
| 315 | 332 | ||
| 316 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | 333 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) |
| 317 | { | 334 | { |
| 318 | struct rb_node *nd; | 335 | struct rb_node *nd; |
| 319 | size_t ret = 0; | 336 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + |
| 337 | __dsos__fprintf(&machines->host.user_dsos, fp); | ||
| 320 | 338 | ||
| 321 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | 339 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
| 322 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 340 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 323 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | 341 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); |
| 324 | ret += __dsos__fprintf(&pos->user_dsos, fp); | 342 | ret += __dsos__fprintf(&pos->user_dsos, fp); |
| @@ -334,13 +352,13 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | |||
| 334 | __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); | 352 | __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); |
| 335 | } | 353 | } |
| 336 | 354 | ||
| 337 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, | 355 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, |
| 338 | bool (skip)(struct dso *dso, int parm), int parm) | 356 | bool (skip)(struct dso *dso, int parm), int parm) |
| 339 | { | 357 | { |
| 340 | struct rb_node *nd; | 358 | struct rb_node *nd; |
| 341 | size_t ret = 0; | 359 | size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); |
| 342 | 360 | ||
| 343 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | 361 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
| 344 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 362 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
| 345 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); | 363 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); |
| 346 | } | 364 | } |
| @@ -511,7 +529,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
| 511 | } | 529 | } |
| 512 | } | 530 | } |
| 513 | 531 | ||
| 514 | int machines__create_guest_kernel_maps(struct rb_root *machines) | 532 | int machines__create_guest_kernel_maps(struct machines *machines) |
| 515 | { | 533 | { |
| 516 | int ret = 0; | 534 | int ret = 0; |
| 517 | struct dirent **namelist = NULL; | 535 | struct dirent **namelist = NULL; |
| @@ -560,20 +578,22 @@ failure: | |||
| 560 | return ret; | 578 | return ret; |
| 561 | } | 579 | } |
| 562 | 580 | ||
| 563 | void machines__destroy_guest_kernel_maps(struct rb_root *machines) | 581 | void machines__destroy_kernel_maps(struct machines *machines) |
| 564 | { | 582 | { |
| 565 | struct rb_node *next = rb_first(machines); | 583 | struct rb_node *next = rb_first(&machines->guests); |
| 584 | |||
| 585 | machine__destroy_kernel_maps(&machines->host); | ||
| 566 | 586 | ||
| 567 | while (next) { | 587 | while (next) { |
| 568 | struct machine *pos = rb_entry(next, struct machine, rb_node); | 588 | struct machine *pos = rb_entry(next, struct machine, rb_node); |
| 569 | 589 | ||
| 570 | next = rb_next(&pos->rb_node); | 590 | next = rb_next(&pos->rb_node); |
| 571 | rb_erase(&pos->rb_node, machines); | 591 | rb_erase(&pos->rb_node, &machines->guests); |
| 572 | machine__delete(pos); | 592 | machine__delete(pos); |
| 573 | } | 593 | } |
| 574 | } | 594 | } |
| 575 | 595 | ||
| 576 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | 596 | int machines__create_kernel_maps(struct machines *machines, pid_t pid) |
| 577 | { | 597 | { |
| 578 | struct machine *machine = machines__findnew(machines, pid); | 598 | struct machine *machine = machines__findnew(machines, pid); |
| 579 | 599 | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e11236878ec1..5ac5892f2326 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
| @@ -47,16 +47,24 @@ int machine__process_event(struct machine *machine, union perf_event *event); | |||
| 47 | 47 | ||
| 48 | typedef void (*machine__process_t)(struct machine *machine, void *data); | 48 | typedef void (*machine__process_t)(struct machine *machine, void *data); |
| 49 | 49 | ||
| 50 | void machines__process(struct rb_root *machines, | 50 | struct machines { |
| 51 | machine__process_t process, void *data); | 51 | struct machine host; |
| 52 | struct rb_root guests; | ||
| 53 | }; | ||
| 54 | |||
| 55 | void machines__init(struct machines *machines); | ||
| 56 | void machines__exit(struct machines *machines); | ||
| 57 | |||
| 58 | void machines__process_guests(struct machines *machines, | ||
| 59 | machine__process_t process, void *data); | ||
| 52 | 60 | ||
| 53 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | 61 | struct machine *machines__add(struct machines *machines, pid_t pid, |
| 54 | const char *root_dir); | 62 | const char *root_dir); |
| 55 | struct machine *machines__find_host(struct rb_root *machines); | 63 | struct machine *machines__find_host(struct machines *machines); |
| 56 | struct machine *machines__find(struct rb_root *machines, pid_t pid); | 64 | struct machine *machines__find(struct machines *machines, pid_t pid); |
| 57 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid); | 65 | struct machine *machines__findnew(struct machines *machines, pid_t pid); |
| 58 | 66 | ||
| 59 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); | 67 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); |
| 60 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | 68 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size); |
| 61 | 69 | ||
| 62 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 70 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
| @@ -132,17 +140,17 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | |||
| 132 | 140 | ||
| 133 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | 141 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
| 134 | bool (skip)(struct dso *dso, int parm), int parm); | 142 | bool (skip)(struct dso *dso, int parm), int parm); |
| 135 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); | 143 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp); |
| 136 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, | 144 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, |
| 137 | bool (skip)(struct dso *dso, int parm), int parm); | 145 | bool (skip)(struct dso *dso, int parm), int parm); |
| 138 | 146 | ||
| 139 | void machine__destroy_kernel_maps(struct machine *machine); | 147 | void machine__destroy_kernel_maps(struct machine *machine); |
| 140 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | 148 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); |
| 141 | int machine__create_kernel_maps(struct machine *machine); | 149 | int machine__create_kernel_maps(struct machine *machine); |
| 142 | 150 | ||
| 143 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); | 151 | int machines__create_kernel_maps(struct machines *machines, pid_t pid); |
| 144 | int machines__create_guest_kernel_maps(struct rb_root *machines); | 152 | int machines__create_guest_kernel_maps(struct machines *machines); |
| 145 | void machines__destroy_guest_kernel_maps(struct rb_root *machines); | 153 | void machines__destroy_kernel_maps(struct machines *machines); |
| 146 | 154 | ||
| 147 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); | 155 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); |
| 148 | 156 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 0328d45c4f2a..ff94425779a2 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -19,7 +19,8 @@ const char *map_type__name[MAP__NR_TYPES] = { | |||
| 19 | 19 | ||
| 20 | static inline int is_anon_memory(const char *filename) | 20 | static inline int is_anon_memory(const char *filename) |
| 21 | { | 21 | { |
| 22 | return strcmp(filename, "//anon") == 0; | 22 | return !strcmp(filename, "//anon") || |
| 23 | !strcmp(filename, "/anon_hugepage (deleted)"); | ||
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | static inline int is_no_dso_memory(const char *filename) | 26 | static inline int is_no_dso_memory(const char *filename) |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2d8d53bec17e..02f6421f03a0 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx, | |||
| 380 | return 0; | 380 | return 0; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | static int add_tracepoint_multi(struct list_head **list, int *idx, | 383 | static int add_tracepoint_multi_event(struct list_head **list, int *idx, |
| 384 | char *sys_name, char *evt_name) | 384 | char *sys_name, char *evt_name) |
| 385 | { | 385 | { |
| 386 | char evt_path[MAXPATHLEN]; | 386 | char evt_path[MAXPATHLEN]; |
| 387 | struct dirent *evt_ent; | 387 | struct dirent *evt_ent; |
| @@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx, | |||
| 408 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); | 408 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | closedir(evt_dir); | ||
| 412 | return ret; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int add_tracepoint_event(struct list_head **list, int *idx, | ||
| 416 | char *sys_name, char *evt_name) | ||
| 417 | { | ||
| 418 | return strpbrk(evt_name, "*?") ? | ||
| 419 | add_tracepoint_multi_event(list, idx, sys_name, evt_name) : | ||
| 420 | add_tracepoint(list, idx, sys_name, evt_name); | ||
| 421 | } | ||
| 422 | |||
| 423 | static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | ||
| 424 | char *sys_name, char *evt_name) | ||
| 425 | { | ||
| 426 | struct dirent *events_ent; | ||
| 427 | DIR *events_dir; | ||
| 428 | int ret = 0; | ||
| 429 | |||
| 430 | events_dir = opendir(tracing_events_path); | ||
| 431 | if (!events_dir) { | ||
| 432 | perror("Can't open event dir"); | ||
| 433 | return -1; | ||
| 434 | } | ||
| 435 | |||
| 436 | while (!ret && (events_ent = readdir(events_dir))) { | ||
| 437 | if (!strcmp(events_ent->d_name, ".") | ||
| 438 | || !strcmp(events_ent->d_name, "..") | ||
| 439 | || !strcmp(events_ent->d_name, "enable") | ||
| 440 | || !strcmp(events_ent->d_name, "header_event") | ||
| 441 | || !strcmp(events_ent->d_name, "header_page")) | ||
| 442 | continue; | ||
| 443 | |||
| 444 | if (!strglobmatch(events_ent->d_name, sys_name)) | ||
| 445 | continue; | ||
| 446 | |||
| 447 | ret = add_tracepoint_event(list, idx, events_ent->d_name, | ||
| 448 | evt_name); | ||
| 449 | } | ||
| 450 | |||
| 451 | closedir(events_dir); | ||
| 411 | return ret; | 452 | return ret; |
| 412 | } | 453 | } |
| 413 | 454 | ||
| @@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx, | |||
| 420 | if (ret) | 461 | if (ret) |
| 421 | return ret; | 462 | return ret; |
| 422 | 463 | ||
| 423 | return strpbrk(event, "*?") ? | 464 | if (strpbrk(sys, "*?")) |
| 424 | add_tracepoint_multi(list, idx, sys, event) : | 465 | return add_tracepoint_multi_sys(list, idx, sys, event); |
| 425 | add_tracepoint(list, idx, sys, event); | 466 | else |
| 467 | return add_tracepoint_event(list, idx, sys, event); | ||
| 426 | } | 468 | } |
| 427 | 469 | ||
| 428 | static int | 470 | static int |
| @@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, | |||
| 492 | } | 534 | } |
| 493 | 535 | ||
| 494 | static int config_term(struct perf_event_attr *attr, | 536 | static int config_term(struct perf_event_attr *attr, |
| 495 | struct parse_events__term *term) | 537 | struct parse_events_term *term) |
| 496 | { | 538 | { |
| 497 | #define CHECK_TYPE_VAL(type) \ | 539 | #define CHECK_TYPE_VAL(type) \ |
| 498 | do { \ | 540 | do { \ |
| @@ -537,7 +579,7 @@ do { \ | |||
| 537 | static int config_attr(struct perf_event_attr *attr, | 579 | static int config_attr(struct perf_event_attr *attr, |
| 538 | struct list_head *head, int fail) | 580 | struct list_head *head, int fail) |
| 539 | { | 581 | { |
| 540 | struct parse_events__term *term; | 582 | struct parse_events_term *term; |
| 541 | 583 | ||
| 542 | list_for_each_entry(term, head, list) | 584 | list_for_each_entry(term, head, list) |
| 543 | if (config_term(attr, term) && fail) | 585 | if (config_term(attr, term) && fail) |
| @@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx, | |||
| 563 | return add_event(list, idx, &attr, NULL); | 605 | return add_event(list, idx, &attr, NULL); |
| 564 | } | 606 | } |
| 565 | 607 | ||
| 566 | static int parse_events__is_name_term(struct parse_events__term *term) | 608 | static int parse_events__is_name_term(struct parse_events_term *term) |
| 567 | { | 609 | { |
| 568 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; | 610 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; |
| 569 | } | 611 | } |
| 570 | 612 | ||
| 571 | static char *pmu_event_name(struct list_head *head_terms) | 613 | static char *pmu_event_name(struct list_head *head_terms) |
| 572 | { | 614 | { |
| 573 | struct parse_events__term *term; | 615 | struct parse_events_term *term; |
| 574 | 616 | ||
| 575 | list_for_each_entry(term, head_terms, list) | 617 | list_for_each_entry(term, head_terms, list) |
| 576 | if (parse_events__is_name_term(term)) | 618 | if (parse_events__is_name_term(term)) |
| @@ -814,7 +856,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token) | |||
| 814 | */ | 856 | */ |
| 815 | int parse_events_terms(struct list_head *terms, const char *str) | 857 | int parse_events_terms(struct list_head *terms, const char *str) |
| 816 | { | 858 | { |
| 817 | struct parse_events_data__terms data = { | 859 | struct parse_events_terms data = { |
| 818 | .terms = NULL, | 860 | .terms = NULL, |
| 819 | }; | 861 | }; |
| 820 | int ret; | 862 | int ret; |
| @@ -830,10 +872,9 @@ int parse_events_terms(struct list_head *terms, const char *str) | |||
| 830 | return ret; | 872 | return ret; |
| 831 | } | 873 | } |
| 832 | 874 | ||
| 833 | int parse_events(struct perf_evlist *evlist, const char *str, | 875 | int parse_events(struct perf_evlist *evlist, const char *str) |
| 834 | int unset __maybe_unused) | ||
| 835 | { | 876 | { |
| 836 | struct parse_events_data__events data = { | 877 | struct parse_events_evlist data = { |
| 837 | .list = LIST_HEAD_INIT(data.list), | 878 | .list = LIST_HEAD_INIT(data.list), |
| 838 | .idx = evlist->nr_entries, | 879 | .idx = evlist->nr_entries, |
| 839 | }; | 880 | }; |
| @@ -858,7 +899,7 @@ int parse_events_option(const struct option *opt, const char *str, | |||
| 858 | int unset __maybe_unused) | 899 | int unset __maybe_unused) |
| 859 | { | 900 | { |
| 860 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | 901 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
| 861 | int ret = parse_events(evlist, str, unset); | 902 | int ret = parse_events(evlist, str); |
| 862 | 903 | ||
| 863 | if (ret) { | 904 | if (ret) { |
| 864 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); | 905 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); |
| @@ -1121,16 +1162,16 @@ void print_events(const char *event_glob, bool name_only) | |||
| 1121 | print_tracepoint_events(NULL, NULL, name_only); | 1162 | print_tracepoint_events(NULL, NULL, name_only); |
| 1122 | } | 1163 | } |
| 1123 | 1164 | ||
| 1124 | int parse_events__is_hardcoded_term(struct parse_events__term *term) | 1165 | int parse_events__is_hardcoded_term(struct parse_events_term *term) |
| 1125 | { | 1166 | { |
| 1126 | return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; | 1167 | return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; |
| 1127 | } | 1168 | } |
| 1128 | 1169 | ||
| 1129 | static int new_term(struct parse_events__term **_term, int type_val, | 1170 | static int new_term(struct parse_events_term **_term, int type_val, |
| 1130 | int type_term, char *config, | 1171 | int type_term, char *config, |
| 1131 | char *str, u64 num) | 1172 | char *str, u64 num) |
| 1132 | { | 1173 | { |
| 1133 | struct parse_events__term *term; | 1174 | struct parse_events_term *term; |
| 1134 | 1175 | ||
| 1135 | term = zalloc(sizeof(*term)); | 1176 | term = zalloc(sizeof(*term)); |
| 1136 | if (!term) | 1177 | if (!term) |
| @@ -1156,21 +1197,21 @@ static int new_term(struct parse_events__term **_term, int type_val, | |||
| 1156 | return 0; | 1197 | return 0; |
| 1157 | } | 1198 | } |
| 1158 | 1199 | ||
| 1159 | int parse_events__term_num(struct parse_events__term **term, | 1200 | int parse_events_term__num(struct parse_events_term **term, |
| 1160 | int type_term, char *config, u64 num) | 1201 | int type_term, char *config, u64 num) |
| 1161 | { | 1202 | { |
| 1162 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, | 1203 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, |
| 1163 | config, NULL, num); | 1204 | config, NULL, num); |
| 1164 | } | 1205 | } |
| 1165 | 1206 | ||
| 1166 | int parse_events__term_str(struct parse_events__term **term, | 1207 | int parse_events_term__str(struct parse_events_term **term, |
| 1167 | int type_term, char *config, char *str) | 1208 | int type_term, char *config, char *str) |
| 1168 | { | 1209 | { |
| 1169 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, | 1210 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, |
| 1170 | config, str, 0); | 1211 | config, str, 0); |
| 1171 | } | 1212 | } |
| 1172 | 1213 | ||
| 1173 | int parse_events__term_sym_hw(struct parse_events__term **term, | 1214 | int parse_events_term__sym_hw(struct parse_events_term **term, |
| 1174 | char *config, unsigned idx) | 1215 | char *config, unsigned idx) |
| 1175 | { | 1216 | { |
| 1176 | struct event_symbol *sym; | 1217 | struct event_symbol *sym; |
| @@ -1188,8 +1229,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term, | |||
| 1188 | (char *) "event", (char *) sym->symbol, 0); | 1229 | (char *) "event", (char *) sym->symbol, 0); |
| 1189 | } | 1230 | } |
| 1190 | 1231 | ||
| 1191 | int parse_events__term_clone(struct parse_events__term **new, | 1232 | int parse_events_term__clone(struct parse_events_term **new, |
| 1192 | struct parse_events__term *term) | 1233 | struct parse_events_term *term) |
| 1193 | { | 1234 | { |
| 1194 | return new_term(new, term->type_val, term->type_term, term->config, | 1235 | return new_term(new, term->type_val, term->type_term, term->config, |
| 1195 | term->val.str, term->val.num); | 1236 | term->val.str, term->val.num); |
| @@ -1197,7 +1238,7 @@ int parse_events__term_clone(struct parse_events__term **new, | |||
| 1197 | 1238 | ||
| 1198 | void parse_events__free_terms(struct list_head *terms) | 1239 | void parse_events__free_terms(struct list_head *terms) |
| 1199 | { | 1240 | { |
| 1200 | struct parse_events__term *term, *h; | 1241 | struct parse_events_term *term, *h; |
| 1201 | 1242 | ||
| 1202 | list_for_each_entry_safe(term, h, terms, list) | 1243 | list_for_each_entry_safe(term, h, terms, list) |
| 1203 | free(term); | 1244 | free(term); |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b7af80b8bdda..2cd2c42a69c5 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
| @@ -29,8 +29,7 @@ const char *event_type(int type); | |||
| 29 | 29 | ||
| 30 | extern int parse_events_option(const struct option *opt, const char *str, | 30 | extern int parse_events_option(const struct option *opt, const char *str, |
| 31 | int unset); | 31 | int unset); |
| 32 | extern int parse_events(struct perf_evlist *evlist, const char *str, | 32 | extern int parse_events(struct perf_evlist *evlist, const char *str); |
| 33 | int unset); | ||
| 34 | extern int parse_events_terms(struct list_head *terms, const char *str); | 33 | extern int parse_events_terms(struct list_head *terms, const char *str); |
| 35 | extern int parse_filter(const struct option *opt, const char *str, int unset); | 34 | extern int parse_filter(const struct option *opt, const char *str, int unset); |
| 36 | 35 | ||
| @@ -51,7 +50,7 @@ enum { | |||
| 51 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, | 50 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, |
| 52 | }; | 51 | }; |
| 53 | 52 | ||
| 54 | struct parse_events__term { | 53 | struct parse_events_term { |
| 55 | char *config; | 54 | char *config; |
| 56 | union { | 55 | union { |
| 57 | char *str; | 56 | char *str; |
| @@ -62,24 +61,24 @@ struct parse_events__term { | |||
| 62 | struct list_head list; | 61 | struct list_head list; |
| 63 | }; | 62 | }; |
| 64 | 63 | ||
| 65 | struct parse_events_data__events { | 64 | struct parse_events_evlist { |
| 66 | struct list_head list; | 65 | struct list_head list; |
| 67 | int idx; | 66 | int idx; |
| 68 | }; | 67 | }; |
| 69 | 68 | ||
| 70 | struct parse_events_data__terms { | 69 | struct parse_events_terms { |
| 71 | struct list_head *terms; | 70 | struct list_head *terms; |
| 72 | }; | 71 | }; |
| 73 | 72 | ||
| 74 | int parse_events__is_hardcoded_term(struct parse_events__term *term); | 73 | int parse_events__is_hardcoded_term(struct parse_events_term *term); |
| 75 | int parse_events__term_num(struct parse_events__term **_term, | 74 | int parse_events_term__num(struct parse_events_term **_term, |
| 76 | int type_term, char *config, u64 num); | 75 | int type_term, char *config, u64 num); |
| 77 | int parse_events__term_str(struct parse_events__term **_term, | 76 | int parse_events_term__str(struct parse_events_term **_term, |
| 78 | int type_term, char *config, char *str); | 77 | int type_term, char *config, char *str); |
| 79 | int parse_events__term_sym_hw(struct parse_events__term **term, | 78 | int parse_events_term__sym_hw(struct parse_events_term **term, |
| 80 | char *config, unsigned idx); | 79 | char *config, unsigned idx); |
| 81 | int parse_events__term_clone(struct parse_events__term **new, | 80 | int parse_events_term__clone(struct parse_events_term **new, |
| 82 | struct parse_events__term *term); | 81 | struct parse_events_term *term); |
| 83 | void parse_events__free_terms(struct list_head *terms); | 82 | void parse_events__free_terms(struct list_head *terms); |
| 84 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); | 83 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); |
| 85 | int parse_events__modifier_group(struct list_head *list, char *event_mod); | 84 | int parse_events__modifier_group(struct list_head *list, char *event_mod); |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 0f9914ae6bac..9d43c86176ff 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
| @@ -68,7 +68,7 @@ do { \ | |||
| 68 | char *str; | 68 | char *str; |
| 69 | u64 num; | 69 | u64 num; |
| 70 | struct list_head *head; | 70 | struct list_head *head; |
| 71 | struct parse_events__term *term; | 71 | struct parse_events_term *term; |
| 72 | } | 72 | } |
| 73 | %% | 73 | %% |
| 74 | 74 | ||
| @@ -79,7 +79,7 @@ PE_START_TERMS start_terms | |||
| 79 | 79 | ||
| 80 | start_events: groups | 80 | start_events: groups |
| 81 | { | 81 | { |
| 82 | struct parse_events_data__events *data = _data; | 82 | struct parse_events_evlist *data = _data; |
| 83 | 83 | ||
| 84 | parse_events_update_lists($1, &data->list); | 84 | parse_events_update_lists($1, &data->list); |
| 85 | } | 85 | } |
| @@ -186,7 +186,7 @@ event_def: event_pmu | | |||
| 186 | event_pmu: | 186 | event_pmu: |
| 187 | PE_NAME '/' event_config '/' | 187 | PE_NAME '/' event_config '/' |
| 188 | { | 188 | { |
| 189 | struct parse_events_data__events *data = _data; | 189 | struct parse_events_evlist *data = _data; |
| 190 | struct list_head *list = NULL; | 190 | struct list_head *list = NULL; |
| 191 | 191 | ||
| 192 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); | 192 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); |
| @@ -202,7 +202,7 @@ PE_VALUE_SYM_SW | |||
| 202 | event_legacy_symbol: | 202 | event_legacy_symbol: |
| 203 | value_sym '/' event_config '/' | 203 | value_sym '/' event_config '/' |
| 204 | { | 204 | { |
| 205 | struct parse_events_data__events *data = _data; | 205 | struct parse_events_evlist *data = _data; |
| 206 | struct list_head *list = NULL; | 206 | struct list_head *list = NULL; |
| 207 | int type = $1 >> 16; | 207 | int type = $1 >> 16; |
| 208 | int config = $1 & 255; | 208 | int config = $1 & 255; |
| @@ -215,7 +215,7 @@ value_sym '/' event_config '/' | |||
| 215 | | | 215 | | |
| 216 | value_sym sep_slash_dc | 216 | value_sym sep_slash_dc |
| 217 | { | 217 | { |
| 218 | struct parse_events_data__events *data = _data; | 218 | struct parse_events_evlist *data = _data; |
| 219 | struct list_head *list = NULL; | 219 | struct list_head *list = NULL; |
| 220 | int type = $1 >> 16; | 220 | int type = $1 >> 16; |
| 221 | int config = $1 & 255; | 221 | int config = $1 & 255; |
| @@ -228,7 +228,7 @@ value_sym sep_slash_dc | |||
| 228 | event_legacy_cache: | 228 | event_legacy_cache: |
| 229 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 229 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
| 230 | { | 230 | { |
| 231 | struct parse_events_data__events *data = _data; | 231 | struct parse_events_evlist *data = _data; |
| 232 | struct list_head *list = NULL; | 232 | struct list_head *list = NULL; |
| 233 | 233 | ||
| 234 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); | 234 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); |
| @@ -237,7 +237,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | |||
| 237 | | | 237 | | |
| 238 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 238 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
| 239 | { | 239 | { |
| 240 | struct parse_events_data__events *data = _data; | 240 | struct parse_events_evlist *data = _data; |
| 241 | struct list_head *list = NULL; | 241 | struct list_head *list = NULL; |
| 242 | 242 | ||
| 243 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); | 243 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); |
| @@ -246,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | |||
| 246 | | | 246 | | |
| 247 | PE_NAME_CACHE_TYPE | 247 | PE_NAME_CACHE_TYPE |
| 248 | { | 248 | { |
| 249 | struct parse_events_data__events *data = _data; | 249 | struct parse_events_evlist *data = _data; |
| 250 | struct list_head *list = NULL; | 250 | struct list_head *list = NULL; |
| 251 | 251 | ||
| 252 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); | 252 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); |
| @@ -256,7 +256,7 @@ PE_NAME_CACHE_TYPE | |||
| 256 | event_legacy_mem: | 256 | event_legacy_mem: |
| 257 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 257 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
| 258 | { | 258 | { |
| 259 | struct parse_events_data__events *data = _data; | 259 | struct parse_events_evlist *data = _data; |
| 260 | struct list_head *list = NULL; | 260 | struct list_head *list = NULL; |
| 261 | 261 | ||
| 262 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 262 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
| @@ -266,7 +266,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | |||
| 266 | | | 266 | | |
| 267 | PE_PREFIX_MEM PE_VALUE sep_dc | 267 | PE_PREFIX_MEM PE_VALUE sep_dc |
| 268 | { | 268 | { |
| 269 | struct parse_events_data__events *data = _data; | 269 | struct parse_events_evlist *data = _data; |
| 270 | struct list_head *list = NULL; | 270 | struct list_head *list = NULL; |
| 271 | 271 | ||
| 272 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 272 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
| @@ -277,7 +277,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc | |||
| 277 | event_legacy_tracepoint: | 277 | event_legacy_tracepoint: |
| 278 | PE_NAME ':' PE_NAME | 278 | PE_NAME ':' PE_NAME |
| 279 | { | 279 | { |
| 280 | struct parse_events_data__events *data = _data; | 280 | struct parse_events_evlist *data = _data; |
| 281 | struct list_head *list = NULL; | 281 | struct list_head *list = NULL; |
| 282 | 282 | ||
| 283 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); | 283 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); |
| @@ -287,7 +287,7 @@ PE_NAME ':' PE_NAME | |||
| 287 | event_legacy_numeric: | 287 | event_legacy_numeric: |
| 288 | PE_VALUE ':' PE_VALUE | 288 | PE_VALUE ':' PE_VALUE |
| 289 | { | 289 | { |
| 290 | struct parse_events_data__events *data = _data; | 290 | struct parse_events_evlist *data = _data; |
| 291 | struct list_head *list = NULL; | 291 | struct list_head *list = NULL; |
| 292 | 292 | ||
| 293 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); | 293 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); |
| @@ -297,7 +297,7 @@ PE_VALUE ':' PE_VALUE | |||
| 297 | event_legacy_raw: | 297 | event_legacy_raw: |
| 298 | PE_RAW | 298 | PE_RAW |
| 299 | { | 299 | { |
| 300 | struct parse_events_data__events *data = _data; | 300 | struct parse_events_evlist *data = _data; |
| 301 | struct list_head *list = NULL; | 301 | struct list_head *list = NULL; |
| 302 | 302 | ||
| 303 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, | 303 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
| @@ -307,7 +307,7 @@ PE_RAW | |||
| 307 | 307 | ||
| 308 | start_terms: event_config | 308 | start_terms: event_config |
| 309 | { | 309 | { |
| 310 | struct parse_events_data__terms *data = _data; | 310 | struct parse_events_terms *data = _data; |
| 311 | data->terms = $1; | 311 | data->terms = $1; |
| 312 | } | 312 | } |
| 313 | 313 | ||
| @@ -315,7 +315,7 @@ event_config: | |||
| 315 | event_config ',' event_term | 315 | event_config ',' event_term |
| 316 | { | 316 | { |
| 317 | struct list_head *head = $1; | 317 | struct list_head *head = $1; |
| 318 | struct parse_events__term *term = $3; | 318 | struct parse_events_term *term = $3; |
| 319 | 319 | ||
| 320 | ABORT_ON(!head); | 320 | ABORT_ON(!head); |
| 321 | list_add_tail(&term->list, head); | 321 | list_add_tail(&term->list, head); |
| @@ -325,7 +325,7 @@ event_config ',' event_term | |||
| 325 | event_term | 325 | event_term |
| 326 | { | 326 | { |
| 327 | struct list_head *head = malloc(sizeof(*head)); | 327 | struct list_head *head = malloc(sizeof(*head)); |
| 328 | struct parse_events__term *term = $1; | 328 | struct parse_events_term *term = $1; |
| 329 | 329 | ||
| 330 | ABORT_ON(!head); | 330 | ABORT_ON(!head); |
| 331 | INIT_LIST_HEAD(head); | 331 | INIT_LIST_HEAD(head); |
| @@ -336,70 +336,70 @@ event_term | |||
| 336 | event_term: | 336 | event_term: |
| 337 | PE_NAME '=' PE_NAME | 337 | PE_NAME '=' PE_NAME |
| 338 | { | 338 | { |
| 339 | struct parse_events__term *term; | 339 | struct parse_events_term *term; |
| 340 | 340 | ||
| 341 | ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, | 341 | ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, |
| 342 | $1, $3)); | 342 | $1, $3)); |
| 343 | $$ = term; | 343 | $$ = term; |
| 344 | } | 344 | } |
| 345 | | | 345 | | |
| 346 | PE_NAME '=' PE_VALUE | 346 | PE_NAME '=' PE_VALUE |
| 347 | { | 347 | { |
| 348 | struct parse_events__term *term; | 348 | struct parse_events_term *term; |
| 349 | 349 | ||
| 350 | ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, | 350 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, |
| 351 | $1, $3)); | 351 | $1, $3)); |
| 352 | $$ = term; | 352 | $$ = term; |
| 353 | } | 353 | } |
| 354 | | | 354 | | |
| 355 | PE_NAME '=' PE_VALUE_SYM_HW | 355 | PE_NAME '=' PE_VALUE_SYM_HW |
| 356 | { | 356 | { |
| 357 | struct parse_events__term *term; | 357 | struct parse_events_term *term; |
| 358 | int config = $3 & 255; | 358 | int config = $3 & 255; |
| 359 | 359 | ||
| 360 | ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); | 360 | ABORT_ON(parse_events_term__sym_hw(&term, $1, config)); |
| 361 | $$ = term; | 361 | $$ = term; |
| 362 | } | 362 | } |
| 363 | | | 363 | | |
| 364 | PE_NAME | 364 | PE_NAME |
| 365 | { | 365 | { |
| 366 | struct parse_events__term *term; | 366 | struct parse_events_term *term; |
| 367 | 367 | ||
| 368 | ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, | 368 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, |
| 369 | $1, 1)); | 369 | $1, 1)); |
| 370 | $$ = term; | 370 | $$ = term; |
| 371 | } | 371 | } |
| 372 | | | 372 | | |
| 373 | PE_VALUE_SYM_HW | 373 | PE_VALUE_SYM_HW |
| 374 | { | 374 | { |
| 375 | struct parse_events__term *term; | 375 | struct parse_events_term *term; |
| 376 | int config = $1 & 255; | 376 | int config = $1 & 255; |
| 377 | 377 | ||
| 378 | ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); | 378 | ABORT_ON(parse_events_term__sym_hw(&term, NULL, config)); |
| 379 | $$ = term; | 379 | $$ = term; |
| 380 | } | 380 | } |
| 381 | | | 381 | | |
| 382 | PE_TERM '=' PE_NAME | 382 | PE_TERM '=' PE_NAME |
| 383 | { | 383 | { |
| 384 | struct parse_events__term *term; | 384 | struct parse_events_term *term; |
| 385 | 385 | ||
| 386 | ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); | 386 | ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3)); |
| 387 | $$ = term; | 387 | $$ = term; |
| 388 | } | 388 | } |
| 389 | | | 389 | | |
| 390 | PE_TERM '=' PE_VALUE | 390 | PE_TERM '=' PE_VALUE |
| 391 | { | 391 | { |
| 392 | struct parse_events__term *term; | 392 | struct parse_events_term *term; |
| 393 | 393 | ||
| 394 | ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); | 394 | ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3)); |
| 395 | $$ = term; | 395 | $$ = term; |
| 396 | } | 396 | } |
| 397 | | | 397 | | |
| 398 | PE_TERM | 398 | PE_TERM |
| 399 | { | 399 | { |
| 400 | struct parse_events__term *term; | 400 | struct parse_events_term *term; |
| 401 | 401 | ||
| 402 | ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); | 402 | ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1)); |
| 403 | $$ = term; | 403 | $$ = term; |
| 404 | } | 404 | } |
| 405 | 405 | ||
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 9bdc60c6f138..4c6f9c490a8d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | |||
| 2 | #include <linux/list.h> | 1 | #include <linux/list.h> |
| 3 | #include <sys/types.h> | 2 | #include <sys/types.h> |
| 4 | #include <sys/stat.h> | 3 | #include <sys/stat.h> |
| @@ -11,6 +10,19 @@ | |||
| 11 | #include "parse-events.h" | 10 | #include "parse-events.h" |
| 12 | #include "cpumap.h" | 11 | #include "cpumap.h" |
| 13 | 12 | ||
| 13 | struct perf_pmu_alias { | ||
| 14 | char *name; | ||
| 15 | struct list_head terms; | ||
| 16 | struct list_head list; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct perf_pmu_format { | ||
| 20 | char *name; | ||
| 21 | int value; | ||
| 22 | DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); | ||
| 23 | struct list_head list; | ||
| 24 | }; | ||
| 25 | |||
| 14 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" | 26 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" |
| 15 | 27 | ||
| 16 | int perf_pmu_parse(struct list_head *list, char *name); | 28 | int perf_pmu_parse(struct list_head *list, char *name); |
| @@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format) | |||
| 85 | 97 | ||
| 86 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | 98 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) |
| 87 | { | 99 | { |
| 88 | struct perf_pmu__alias *alias; | 100 | struct perf_pmu_alias *alias; |
| 89 | char buf[256]; | 101 | char buf[256]; |
| 90 | int ret; | 102 | int ret; |
| 91 | 103 | ||
| @@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head) | |||
| 172 | return 0; | 184 | return 0; |
| 173 | } | 185 | } |
| 174 | 186 | ||
| 175 | static int pmu_alias_terms(struct perf_pmu__alias *alias, | 187 | static int pmu_alias_terms(struct perf_pmu_alias *alias, |
| 176 | struct list_head *terms) | 188 | struct list_head *terms) |
| 177 | { | 189 | { |
| 178 | struct parse_events__term *term, *clone; | 190 | struct parse_events_term *term, *clone; |
| 179 | LIST_HEAD(list); | 191 | LIST_HEAD(list); |
| 180 | int ret; | 192 | int ret; |
| 181 | 193 | ||
| 182 | list_for_each_entry(term, &alias->terms, list) { | 194 | list_for_each_entry(term, &alias->terms, list) { |
| 183 | ret = parse_events__term_clone(&clone, term); | 195 | ret = parse_events_term__clone(&clone, term); |
| 184 | if (ret) { | 196 | if (ret) { |
| 185 | parse_events__free_terms(&list); | 197 | parse_events__free_terms(&list); |
| 186 | return ret; | 198 | return ret; |
| @@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name) | |||
| 360 | return pmu_lookup(name); | 372 | return pmu_lookup(name); |
| 361 | } | 373 | } |
| 362 | 374 | ||
| 363 | static struct perf_pmu__format* | 375 | static struct perf_pmu_format * |
| 364 | pmu_find_format(struct list_head *formats, char *name) | 376 | pmu_find_format(struct list_head *formats, char *name) |
| 365 | { | 377 | { |
| 366 | struct perf_pmu__format *format; | 378 | struct perf_pmu_format *format; |
| 367 | 379 | ||
| 368 | list_for_each_entry(format, formats, list) | 380 | list_for_each_entry(format, formats, list) |
| 369 | if (!strcmp(format->name, name)) | 381 | if (!strcmp(format->name, name)) |
| @@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) | |||
| 403 | */ | 415 | */ |
| 404 | static int pmu_config_term(struct list_head *formats, | 416 | static int pmu_config_term(struct list_head *formats, |
| 405 | struct perf_event_attr *attr, | 417 | struct perf_event_attr *attr, |
| 406 | struct parse_events__term *term) | 418 | struct parse_events_term *term) |
| 407 | { | 419 | { |
| 408 | struct perf_pmu__format *format; | 420 | struct perf_pmu_format *format; |
| 409 | __u64 *vp; | 421 | __u64 *vp; |
| 410 | 422 | ||
| 411 | /* | 423 | /* |
| @@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
| 450 | struct perf_event_attr *attr, | 462 | struct perf_event_attr *attr, |
| 451 | struct list_head *head_terms) | 463 | struct list_head *head_terms) |
| 452 | { | 464 | { |
| 453 | struct parse_events__term *term; | 465 | struct parse_events_term *term; |
| 454 | 466 | ||
| 455 | list_for_each_entry(term, head_terms, list) | 467 | list_for_each_entry(term, head_terms, list) |
| 456 | if (pmu_config_term(formats, attr, term)) | 468 | if (pmu_config_term(formats, attr, term)) |
| @@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
| 471 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); | 483 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); |
| 472 | } | 484 | } |
| 473 | 485 | ||
| 474 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | 486 | static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, |
| 475 | struct parse_events__term *term) | 487 | struct parse_events_term *term) |
| 476 | { | 488 | { |
| 477 | struct perf_pmu__alias *alias; | 489 | struct perf_pmu_alias *alias; |
| 478 | char *name; | 490 | char *name; |
| 479 | 491 | ||
| 480 | if (parse_events__is_hardcoded_term(term)) | 492 | if (parse_events__is_hardcoded_term(term)) |
| @@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | |||
| 507 | */ | 519 | */ |
| 508 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | 520 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) |
| 509 | { | 521 | { |
| 510 | struct parse_events__term *term, *h; | 522 | struct parse_events_term *term, *h; |
| 511 | struct perf_pmu__alias *alias; | 523 | struct perf_pmu_alias *alias; |
| 512 | int ret; | 524 | int ret; |
| 513 | 525 | ||
| 514 | list_for_each_entry_safe(term, h, head_terms, list) { | 526 | list_for_each_entry_safe(term, h, head_terms, list) { |
| @@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | |||
| 527 | int perf_pmu__new_format(struct list_head *list, char *name, | 539 | int perf_pmu__new_format(struct list_head *list, char *name, |
| 528 | int config, unsigned long *bits) | 540 | int config, unsigned long *bits) |
| 529 | { | 541 | { |
| 530 | struct perf_pmu__format *format; | 542 | struct perf_pmu_format *format; |
| 531 | 543 | ||
| 532 | format = zalloc(sizeof(*format)); | 544 | format = zalloc(sizeof(*format)); |
| 533 | if (!format) | 545 | if (!format) |
| @@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) | |||
| 548 | if (!to) | 560 | if (!to) |
| 549 | to = from; | 561 | to = from; |
| 550 | 562 | ||
| 551 | memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); | 563 | memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); |
| 552 | for (b = from; b <= to; b++) | 564 | for (b = from; b <= to; b++) |
| 553 | set_bit(b, bits); | 565 | set_bit(b, bits); |
| 554 | } | 566 | } |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index a313ed76a49a..32fe55b659fa 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
| @@ -12,19 +12,6 @@ enum { | |||
| 12 | 12 | ||
| 13 | #define PERF_PMU_FORMAT_BITS 64 | 13 | #define PERF_PMU_FORMAT_BITS 64 |
| 14 | 14 | ||
| 15 | struct perf_pmu__format { | ||
| 16 | char *name; | ||
| 17 | int value; | ||
| 18 | DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); | ||
| 19 | struct list_head list; | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct perf_pmu__alias { | ||
| 23 | char *name; | ||
| 24 | struct list_head terms; | ||
| 25 | struct list_head list; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct perf_pmu { | 15 | struct perf_pmu { |
| 29 | char *name; | 16 | char *name; |
| 30 | __u32 type; | 17 | __u32 type; |
| @@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
| 42 | struct list_head *head_terms); | 29 | struct list_head *head_terms); |
| 43 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | 30 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); |
| 44 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 31 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
| 45 | struct list_head *head_terms); | 32 | struct list_head *head_terms); |
| 46 | int perf_pmu_wrap(void); | 33 | int perf_pmu_wrap(void); |
| 47 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); | 34 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); |
| 48 | 35 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1daf5c14e751..be0329394d56 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
| 413 | dwarf_diename(vr_die), dwarf_diename(&type)); | 413 | dwarf_diename(vr_die), dwarf_diename(&type)); |
| 414 | return -EINVAL; | 414 | return -EINVAL; |
| 415 | } | 415 | } |
| 416 | if (die_get_real_type(&type, &type) == NULL) { | ||
| 417 | pr_warning("Failed to get a type" | ||
| 418 | " information.\n"); | ||
| 419 | return -ENOENT; | ||
| 420 | } | ||
| 416 | if (ret == DW_TAG_pointer_type) { | 421 | if (ret == DW_TAG_pointer_type) { |
| 417 | if (die_get_real_type(&type, &type) == NULL) { | ||
| 418 | pr_warning("Failed to get a type" | ||
| 419 | " information.\n"); | ||
| 420 | return -ENOENT; | ||
| 421 | } | ||
| 422 | while (*ref_ptr) | 422 | while (*ref_ptr) |
| 423 | ref_ptr = &(*ref_ptr)->next; | 423 | ref_ptr = &(*ref_ptr)->next; |
| 424 | /* Add new reference with offset +0 */ | 424 | /* Add new reference with offset +0 */ |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a2657fd96837..925e0c3e6d91 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -1045,3 +1045,12 @@ error: | |||
| 1045 | if (PyErr_Occurred()) | 1045 | if (PyErr_Occurred()) |
| 1046 | PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); | 1046 | PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); |
| 1047 | } | 1047 | } |
| 1048 | |||
| 1049 | /* | ||
| 1050 | * Dummy, to avoid dragging all the test_attr infrastructure in the python | ||
| 1051 | * binding. | ||
| 1052 | */ | ||
| 1053 | void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, | ||
| 1054 | int fd, int group_fd, unsigned long flags) | ||
| 1055 | { | ||
| 1056 | } | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index f80605eb1855..eacec859f299 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
| @@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
| 292 | ns = nsecs - s * NSECS_PER_SEC; | 292 | ns = nsecs - s * NSECS_PER_SEC; |
| 293 | 293 | ||
| 294 | scripting_context->event_data = data; | 294 | scripting_context->event_data = data; |
| 295 | scripting_context->pevent = evsel->tp_format->pevent; | ||
| 295 | 296 | ||
| 296 | ENTER; | 297 | ENTER; |
| 297 | SAVETMPS; | 298 | SAVETMPS; |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 14683dfca2ee..e87aa5d9696b 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
| 265 | ns = nsecs - s * NSECS_PER_SEC; | 265 | ns = nsecs - s * NSECS_PER_SEC; |
| 266 | 266 | ||
| 267 | scripting_context->event_data = data; | 267 | scripting_context->event_data = data; |
| 268 | scripting_context->pevent = evsel->tp_format->pevent; | ||
| 268 | 269 | ||
| 269 | context = PyCObject_FromVoidPtr(scripting_context, NULL); | 270 | context = PyCObject_FromVoidPtr(scripting_context, NULL); |
| 270 | 271 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 76d6e257b8a4..bd85280bb6e8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -86,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session) | |||
| 86 | { | 86 | { |
| 87 | u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); | 87 | u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); |
| 88 | 88 | ||
| 89 | session->host_machine.id_hdr_size = id_hdr_size; | ||
| 90 | machines__set_id_hdr_size(&session->machines, id_hdr_size); | 89 | machines__set_id_hdr_size(&session->machines, id_hdr_size); |
| 91 | } | 90 | } |
| 92 | 91 | ||
| 93 | int perf_session__create_kernel_maps(struct perf_session *self) | 92 | int perf_session__create_kernel_maps(struct perf_session *self) |
| 94 | { | 93 | { |
| 95 | int ret = machine__create_kernel_maps(&self->host_machine); | 94 | int ret = machine__create_kernel_maps(&self->machines.host); |
| 96 | 95 | ||
| 97 | if (ret >= 0) | 96 | if (ret >= 0) |
| 98 | ret = machines__create_guest_kernel_maps(&self->machines); | 97 | ret = machines__create_guest_kernel_maps(&self->machines); |
| @@ -101,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self) | |||
| 101 | 100 | ||
| 102 | static void perf_session__destroy_kernel_maps(struct perf_session *self) | 101 | static void perf_session__destroy_kernel_maps(struct perf_session *self) |
| 103 | { | 102 | { |
| 104 | machine__destroy_kernel_maps(&self->host_machine); | 103 | machines__destroy_kernel_maps(&self->machines); |
| 105 | machines__destroy_guest_kernel_maps(&self->machines); | ||
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | struct perf_session *perf_session__new(const char *filename, int mode, | 106 | struct perf_session *perf_session__new(const char *filename, int mode, |
| @@ -127,13 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
| 127 | goto out; | 125 | goto out; |
| 128 | 126 | ||
| 129 | memcpy(self->filename, filename, len); | 127 | memcpy(self->filename, filename, len); |
| 130 | self->machines = RB_ROOT; | ||
| 131 | self->repipe = repipe; | 128 | self->repipe = repipe; |
| 132 | INIT_LIST_HEAD(&self->ordered_samples.samples); | 129 | INIT_LIST_HEAD(&self->ordered_samples.samples); |
| 133 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); | 130 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); |
| 134 | INIT_LIST_HEAD(&self->ordered_samples.to_free); | 131 | INIT_LIST_HEAD(&self->ordered_samples.to_free); |
| 135 | machine__init(&self->host_machine, "", HOST_KERNEL_ID); | 132 | machines__init(&self->machines); |
| 136 | hists__init(&self->hists); | ||
| 137 | 133 | ||
| 138 | if (mode == O_RDONLY) { | 134 | if (mode == O_RDONLY) { |
| 139 | if (perf_session__open(self, force) < 0) | 135 | if (perf_session__open(self, force) < 0) |
| @@ -163,12 +159,12 @@ out_delete: | |||
| 163 | 159 | ||
| 164 | static void perf_session__delete_dead_threads(struct perf_session *session) | 160 | static void perf_session__delete_dead_threads(struct perf_session *session) |
| 165 | { | 161 | { |
| 166 | machine__delete_dead_threads(&session->host_machine); | 162 | machine__delete_dead_threads(&session->machines.host); |
| 167 | } | 163 | } |
| 168 | 164 | ||
| 169 | static void perf_session__delete_threads(struct perf_session *session) | 165 | static void perf_session__delete_threads(struct perf_session *session) |
| 170 | { | 166 | { |
| 171 | machine__delete_threads(&session->host_machine); | 167 | machine__delete_threads(&session->machines.host); |
| 172 | } | 168 | } |
| 173 | 169 | ||
| 174 | static void perf_session_env__delete(struct perf_session_env *env) | 170 | static void perf_session_env__delete(struct perf_session_env *env) |
| @@ -193,7 +189,7 @@ void perf_session__delete(struct perf_session *self) | |||
| 193 | perf_session__delete_dead_threads(self); | 189 | perf_session__delete_dead_threads(self); |
| 194 | perf_session__delete_threads(self); | 190 | perf_session__delete_threads(self); |
| 195 | perf_session_env__delete(&self->header.env); | 191 | perf_session_env__delete(&self->header.env); |
| 196 | machine__exit(&self->host_machine); | 192 | machines__exit(&self->machines); |
| 197 | close(self->fd); | 193 | close(self->fd); |
| 198 | free(self); | 194 | free(self); |
| 199 | vdso__exit(); | 195 | vdso__exit(); |
| @@ -825,7 +821,7 @@ static struct machine * | |||
| 825 | return perf_session__findnew_machine(session, pid); | 821 | return perf_session__findnew_machine(session, pid); |
| 826 | } | 822 | } |
| 827 | 823 | ||
| 828 | return perf_session__find_host_machine(session); | 824 | return &session->machines.host; |
| 829 | } | 825 | } |
| 830 | 826 | ||
| 831 | static int perf_session_deliver_event(struct perf_session *session, | 827 | static int perf_session_deliver_event(struct perf_session *session, |
| @@ -863,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 863 | case PERF_RECORD_SAMPLE: | 859 | case PERF_RECORD_SAMPLE: |
| 864 | dump_sample(evsel, event, sample); | 860 | dump_sample(evsel, event, sample); |
| 865 | if (evsel == NULL) { | 861 | if (evsel == NULL) { |
| 866 | ++session->hists.stats.nr_unknown_id; | 862 | ++session->stats.nr_unknown_id; |
| 867 | return 0; | 863 | return 0; |
| 868 | } | 864 | } |
| 869 | if (machine == NULL) { | 865 | if (machine == NULL) { |
| 870 | ++session->hists.stats.nr_unprocessable_samples; | 866 | ++session->stats.nr_unprocessable_samples; |
| 871 | return 0; | 867 | return 0; |
| 872 | } | 868 | } |
| 873 | return tool->sample(tool, event, sample, evsel, machine); | 869 | return tool->sample(tool, event, sample, evsel, machine); |
| @@ -881,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 881 | return tool->exit(tool, event, sample, machine); | 877 | return tool->exit(tool, event, sample, machine); |
| 882 | case PERF_RECORD_LOST: | 878 | case PERF_RECORD_LOST: |
| 883 | if (tool->lost == perf_event__process_lost) | 879 | if (tool->lost == perf_event__process_lost) |
| 884 | session->hists.stats.total_lost += event->lost.lost; | 880 | session->stats.total_lost += event->lost.lost; |
| 885 | return tool->lost(tool, event, sample, machine); | 881 | return tool->lost(tool, event, sample, machine); |
| 886 | case PERF_RECORD_READ: | 882 | case PERF_RECORD_READ: |
| 887 | return tool->read(tool, event, sample, evsel, machine); | 883 | return tool->read(tool, event, sample, evsel, machine); |
| @@ -890,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
| 890 | case PERF_RECORD_UNTHROTTLE: | 886 | case PERF_RECORD_UNTHROTTLE: |
| 891 | return tool->unthrottle(tool, event, sample, machine); | 887 | return tool->unthrottle(tool, event, sample, machine); |
| 892 | default: | 888 | default: |
| 893 | ++session->hists.stats.nr_unknown_events; | 889 | ++session->stats.nr_unknown_events; |
| 894 | return -1; | 890 | return -1; |
| 895 | } | 891 | } |
| 896 | } | 892 | } |
| @@ -904,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session, | |||
| 904 | 900 | ||
| 905 | if (!ip_callchain__valid(sample->callchain, event)) { | 901 | if (!ip_callchain__valid(sample->callchain, event)) { |
| 906 | pr_debug("call-chain problem with event, skipping it.\n"); | 902 | pr_debug("call-chain problem with event, skipping it.\n"); |
| 907 | ++session->hists.stats.nr_invalid_chains; | 903 | ++session->stats.nr_invalid_chains; |
| 908 | session->hists.stats.total_invalid_chains += sample->period; | 904 | session->stats.total_invalid_chains += sample->period; |
| 909 | return -EINVAL; | 905 | return -EINVAL; |
| 910 | } | 906 | } |
| 911 | return 0; | 907 | return 0; |
| @@ -963,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
| 963 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | 959 | if (event->header.type >= PERF_RECORD_HEADER_MAX) |
| 964 | return -EINVAL; | 960 | return -EINVAL; |
| 965 | 961 | ||
| 966 | hists__inc_nr_events(&session->hists, event->header.type); | 962 | events_stats__inc(&session->stats, event->header.type); |
| 967 | 963 | ||
| 968 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | 964 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) |
| 969 | return perf_session__process_user_event(session, event, tool, file_offset); | 965 | return perf_session__process_user_event(session, event, tool, file_offset); |
| @@ -999,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
| 999 | 995 | ||
| 1000 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | 996 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) |
| 1001 | { | 997 | { |
| 1002 | return machine__findnew_thread(&session->host_machine, pid); | 998 | return machine__findnew_thread(&session->machines.host, pid); |
| 1003 | } | 999 | } |
| 1004 | 1000 | ||
| 1005 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 1001 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
| @@ -1018,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
| 1018 | const struct perf_tool *tool) | 1014 | const struct perf_tool *tool) |
| 1019 | { | 1015 | { |
| 1020 | if (tool->lost == perf_event__process_lost && | 1016 | if (tool->lost == perf_event__process_lost && |
| 1021 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { | 1017 | session->stats.nr_events[PERF_RECORD_LOST] != 0) { |
| 1022 | ui__warning("Processed %d events and lost %d chunks!\n\n" | 1018 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
| 1023 | "Check IO/CPU overload!\n\n", | 1019 | "Check IO/CPU overload!\n\n", |
| 1024 | session->hists.stats.nr_events[0], | 1020 | session->stats.nr_events[0], |
| 1025 | session->hists.stats.nr_events[PERF_RECORD_LOST]); | 1021 | session->stats.nr_events[PERF_RECORD_LOST]); |
| 1026 | } | 1022 | } |
| 1027 | 1023 | ||
| 1028 | if (session->hists.stats.nr_unknown_events != 0) { | 1024 | if (session->stats.nr_unknown_events != 0) { |
| 1029 | ui__warning("Found %u unknown events!\n\n" | 1025 | ui__warning("Found %u unknown events!\n\n" |
| 1030 | "Is this an older tool processing a perf.data " | 1026 | "Is this an older tool processing a perf.data " |
| 1031 | "file generated by a more recent tool?\n\n" | 1027 | "file generated by a more recent tool?\n\n" |
| 1032 | "If that is not the case, consider " | 1028 | "If that is not the case, consider " |
| 1033 | "reporting to linux-kernel@vger.kernel.org.\n\n", | 1029 | "reporting to linux-kernel@vger.kernel.org.\n\n", |
| 1034 | session->hists.stats.nr_unknown_events); | 1030 | session->stats.nr_unknown_events); |
| 1035 | } | 1031 | } |
| 1036 | 1032 | ||
| 1037 | if (session->hists.stats.nr_unknown_id != 0) { | 1033 | if (session->stats.nr_unknown_id != 0) { |
| 1038 | ui__warning("%u samples with id not present in the header\n", | 1034 | ui__warning("%u samples with id not present in the header\n", |
| 1039 | session->hists.stats.nr_unknown_id); | 1035 | session->stats.nr_unknown_id); |
| 1040 | } | 1036 | } |
| 1041 | 1037 | ||
| 1042 | if (session->hists.stats.nr_invalid_chains != 0) { | 1038 | if (session->stats.nr_invalid_chains != 0) { |
| 1043 | ui__warning("Found invalid callchains!\n\n" | 1039 | ui__warning("Found invalid callchains!\n\n" |
| 1044 | "%u out of %u events were discarded for this reason.\n\n" | 1040 | "%u out of %u events were discarded for this reason.\n\n" |
| 1045 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | 1041 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", |
| 1046 | session->hists.stats.nr_invalid_chains, | 1042 | session->stats.nr_invalid_chains, |
| 1047 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | 1043 | session->stats.nr_events[PERF_RECORD_SAMPLE]); |
| 1048 | } | 1044 | } |
| 1049 | 1045 | ||
| 1050 | if (session->hists.stats.nr_unprocessable_samples != 0) { | 1046 | if (session->stats.nr_unprocessable_samples != 0) { |
| 1051 | ui__warning("%u unprocessable samples recorded.\n" | 1047 | ui__warning("%u unprocessable samples recorded.\n" |
| 1052 | "Do you have a KVM guest running and not using 'perf kvm'?\n", | 1048 | "Do you have a KVM guest running and not using 'perf kvm'?\n", |
| 1053 | session->hists.stats.nr_unprocessable_samples); | 1049 | session->stats.nr_unprocessable_samples); |
| 1054 | } | 1050 | } |
| 1055 | } | 1051 | } |
| 1056 | 1052 | ||
| @@ -1336,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | |||
| 1336 | 1332 | ||
| 1337 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) | 1333 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) |
| 1338 | { | 1334 | { |
| 1339 | return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + | 1335 | return machines__fprintf_dsos(&self->machines, fp); |
| 1340 | __dsos__fprintf(&self->host_machine.user_dsos, fp) + | ||
| 1341 | machines__fprintf_dsos(&self->machines, fp); | ||
| 1342 | } | 1336 | } |
| 1343 | 1337 | ||
| 1344 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, | 1338 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, |
| 1345 | bool (skip)(struct dso *dso, int parm), int parm) | 1339 | bool (skip)(struct dso *dso, int parm), int parm) |
| 1346 | { | 1340 | { |
| 1347 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); | 1341 | return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); |
| 1348 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); | ||
| 1349 | } | 1342 | } |
| 1350 | 1343 | ||
| 1351 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | 1344 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) |
| @@ -1353,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
| 1353 | struct perf_evsel *pos; | 1346 | struct perf_evsel *pos; |
| 1354 | size_t ret = fprintf(fp, "Aggregated stats:\n"); | 1347 | size_t ret = fprintf(fp, "Aggregated stats:\n"); |
| 1355 | 1348 | ||
| 1356 | ret += hists__fprintf_nr_events(&session->hists, fp); | 1349 | ret += events_stats__fprintf(&session->stats, fp); |
| 1357 | 1350 | ||
| 1358 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1351 | list_for_each_entry(pos, &session->evlist->entries, node) { |
| 1359 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); | 1352 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
| 1360 | ret += hists__fprintf_nr_events(&pos->hists, fp); | 1353 | ret += events_stats__fprintf(&pos->hists.stats, fp); |
| 1361 | } | 1354 | } |
| 1362 | 1355 | ||
| 1363 | return ret; | 1356 | return ret; |
| @@ -1369,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) | |||
| 1369 | * FIXME: Here we have to actually print all the machines in this | 1362 | * FIXME: Here we have to actually print all the machines in this |
| 1370 | * session, not just the host... | 1363 | * session, not just the host... |
| 1371 | */ | 1364 | */ |
| 1372 | return machine__fprintf(&session->host_machine, fp); | 1365 | return machine__fprintf(&session->machines.host, fp); |
| 1373 | } | 1366 | } |
| 1374 | 1367 | ||
| 1375 | void perf_session__remove_thread(struct perf_session *session, | 1368 | void perf_session__remove_thread(struct perf_session *session, |
| @@ -1378,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session, | |||
| 1378 | /* | 1371 | /* |
| 1379 | * FIXME: This one makes no sense, we need to remove the thread from | 1372 | * FIXME: This one makes no sense, we need to remove the thread from |
| 1380 | * the machine it belongs to, perf_session can have many machines, so | 1373 | * the machine it belongs to, perf_session can have many machines, so |
| 1381 | * doing it always on ->host_machine is wrong. Fix when auditing all | 1374 | * doing it always on ->machines.host is wrong. Fix when auditing all |
| 1382 | * the 'perf kvm' code. | 1375 | * the 'perf kvm' code. |
| 1383 | */ | 1376 | */ |
| 1384 | machine__remove_thread(&session->host_machine, th); | 1377 | machine__remove_thread(&session->machines.host, th); |
| 1385 | } | 1378 | } |
| 1386 | 1379 | ||
| 1387 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 1380 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8c2302504199..b5c0847edfa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -30,15 +30,10 @@ struct ordered_samples { | |||
| 30 | struct perf_session { | 30 | struct perf_session { |
| 31 | struct perf_header header; | 31 | struct perf_header header; |
| 32 | unsigned long size; | 32 | unsigned long size; |
| 33 | struct machine host_machine; | 33 | struct machines machines; |
| 34 | struct rb_root machines; | ||
| 35 | struct perf_evlist *evlist; | 34 | struct perf_evlist *evlist; |
| 36 | struct pevent *pevent; | 35 | struct pevent *pevent; |
| 37 | /* | 36 | struct events_stats stats; |
| 38 | * FIXME: Need to split this up further, we need global | ||
| 39 | * stats + per event stats. | ||
| 40 | */ | ||
| 41 | struct hists hists; | ||
| 42 | int fd; | 37 | int fd; |
| 43 | bool fd_pipe; | 38 | bool fd_pipe; |
| 44 | bool repipe; | 39 | bool repipe; |
| @@ -53,7 +48,7 @@ struct perf_tool; | |||
| 53 | struct perf_session *perf_session__new(const char *filename, int mode, | 48 | struct perf_session *perf_session__new(const char *filename, int mode, |
| 54 | bool force, bool repipe, | 49 | bool force, bool repipe, |
| 55 | struct perf_tool *tool); | 50 | struct perf_tool *tool); |
| 56 | void perf_session__delete(struct perf_session *self); | 51 | void perf_session__delete(struct perf_session *session); |
| 57 | 52 | ||
| 58 | void perf_event_header__bswap(struct perf_event_header *self); | 53 | void perf_event_header__bswap(struct perf_event_header *self); |
| 59 | 54 | ||
| @@ -80,36 +75,17 @@ void perf_session__set_id_hdr_size(struct perf_session *session); | |||
| 80 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | 75 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); |
| 81 | 76 | ||
| 82 | static inline | 77 | static inline |
| 83 | struct machine *perf_session__find_host_machine(struct perf_session *self) | ||
| 84 | { | ||
| 85 | return &self->host_machine; | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline | ||
| 89 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) | 78 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) |
| 90 | { | 79 | { |
| 91 | if (pid == HOST_KERNEL_ID) | ||
| 92 | return &self->host_machine; | ||
| 93 | return machines__find(&self->machines, pid); | 80 | return machines__find(&self->machines, pid); |
| 94 | } | 81 | } |
| 95 | 82 | ||
| 96 | static inline | 83 | static inline |
| 97 | struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) | 84 | struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) |
| 98 | { | 85 | { |
| 99 | if (pid == HOST_KERNEL_ID) | ||
| 100 | return &self->host_machine; | ||
| 101 | return machines__findnew(&self->machines, pid); | 86 | return machines__findnew(&self->machines, pid); |
| 102 | } | 87 | } |
| 103 | 88 | ||
| 104 | static inline | ||
| 105 | void perf_session__process_machines(struct perf_session *self, | ||
| 106 | struct perf_tool *tool, | ||
| 107 | machine__process_t process) | ||
| 108 | { | ||
| 109 | process(&self->host_machine, tool); | ||
| 110 | return machines__process(&self->machines, process, tool); | ||
| 111 | } | ||
| 112 | |||
| 113 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); | 89 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); |
| 114 | size_t perf_session__fprintf(struct perf_session *self, FILE *fp); | 90 | size_t perf_session__fprintf(struct perf_session *self, FILE *fp); |
| 115 | 91 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cfd1c0feb32d..7ad62393aa88 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 60 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, | 60 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, |
| 61 | size_t size, unsigned int width) | 61 | size_t size, unsigned int width) |
| 62 | { | 62 | { |
| 63 | return repsep_snprintf(bf, size, "%*s:%5d", width, | 63 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, |
| 64 | self->thread->comm ?: "", self->thread->pid); | 64 | self->thread->comm ?: "", self->thread->pid); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, | |||
| 97 | return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); | 97 | return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | struct sort_entry sort_comm = { | ||
| 101 | .se_header = "Command", | ||
| 102 | .se_cmp = sort__comm_cmp, | ||
| 103 | .se_collapse = sort__comm_collapse, | ||
| 104 | .se_snprintf = hist_entry__comm_snprintf, | ||
| 105 | .se_width_idx = HISTC_COMM, | ||
| 106 | }; | ||
| 107 | |||
| 108 | /* --sort dso */ | ||
| 109 | |||
| 100 | static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) | 110 | static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) |
| 101 | { | 111 | { |
| 102 | struct dso *dso_l = map_l ? map_l->dso : NULL; | 112 | struct dso *dso_l = map_l ? map_l->dso : NULL; |
| @@ -117,22 +127,38 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) | |||
| 117 | return strcmp(dso_name_l, dso_name_r); | 127 | return strcmp(dso_name_l, dso_name_r); |
| 118 | } | 128 | } |
| 119 | 129 | ||
| 120 | struct sort_entry sort_comm = { | ||
| 121 | .se_header = "Command", | ||
| 122 | .se_cmp = sort__comm_cmp, | ||
| 123 | .se_collapse = sort__comm_collapse, | ||
| 124 | .se_snprintf = hist_entry__comm_snprintf, | ||
| 125 | .se_width_idx = HISTC_COMM, | ||
| 126 | }; | ||
| 127 | |||
| 128 | /* --sort dso */ | ||
| 129 | |||
| 130 | static int64_t | 130 | static int64_t |
| 131 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | 131 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) |
| 132 | { | 132 | { |
| 133 | return _sort__dso_cmp(left->ms.map, right->ms.map); | 133 | return _sort__dso_cmp(left->ms.map, right->ms.map); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | static int _hist_entry__dso_snprintf(struct map *map, char *bf, | ||
| 137 | size_t size, unsigned int width) | ||
| 138 | { | ||
| 139 | if (map && map->dso) { | ||
| 140 | const char *dso_name = !verbose ? map->dso->short_name : | ||
| 141 | map->dso->long_name; | ||
| 142 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); | ||
| 143 | } | ||
| 144 | |||
| 145 | return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); | ||
| 146 | } | ||
| 147 | |||
| 148 | static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | ||
| 149 | size_t size, unsigned int width) | ||
| 150 | { | ||
| 151 | return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); | ||
| 152 | } | ||
| 153 | |||
| 154 | struct sort_entry sort_dso = { | ||
| 155 | .se_header = "Shared Object", | ||
| 156 | .se_cmp = sort__dso_cmp, | ||
| 157 | .se_snprintf = hist_entry__dso_snprintf, | ||
| 158 | .se_width_idx = HISTC_DSO, | ||
| 159 | }; | ||
| 160 | |||
| 161 | /* --sort symbol */ | ||
| 136 | 162 | ||
| 137 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, | 163 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, |
| 138 | u64 ip_l, u64 ip_r) | 164 | u64 ip_l, u64 ip_r) |
| @@ -143,35 +169,35 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, | |||
| 143 | if (sym_l == sym_r) | 169 | if (sym_l == sym_r) |
| 144 | return 0; | 170 | return 0; |
| 145 | 171 | ||
| 146 | if (sym_l) | 172 | ip_l = sym_l->start; |
| 147 | ip_l = sym_l->start; | 173 | ip_r = sym_r->start; |
| 148 | if (sym_r) | ||
| 149 | ip_r = sym_r->start; | ||
| 150 | 174 | ||
| 151 | return (int64_t)(ip_r - ip_l); | 175 | return (int64_t)(ip_r - ip_l); |
| 152 | } | 176 | } |
| 153 | 177 | ||
| 154 | static int _hist_entry__dso_snprintf(struct map *map, char *bf, | 178 | static int64_t |
| 155 | size_t size, unsigned int width) | 179 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
| 156 | { | 180 | { |
| 157 | if (map && map->dso) { | 181 | u64 ip_l, ip_r; |
| 158 | const char *dso_name = !verbose ? map->dso->short_name : | ||
| 159 | map->dso->long_name; | ||
| 160 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); | ||
| 161 | } | ||
| 162 | 182 | ||
| 163 | return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); | 183 | if (!left->ms.sym && !right->ms.sym) |
| 164 | } | 184 | return right->level - left->level; |
| 165 | 185 | ||
| 166 | static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | 186 | if (!left->ms.sym || !right->ms.sym) |
| 167 | size_t size, unsigned int width) | 187 | return cmp_null(left->ms.sym, right->ms.sym); |
| 168 | { | 188 | |
| 169 | return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); | 189 | if (left->ms.sym == right->ms.sym) |
| 190 | return 0; | ||
| 191 | |||
| 192 | ip_l = left->ms.sym->start; | ||
| 193 | ip_r = right->ms.sym->start; | ||
| 194 | |||
| 195 | return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); | ||
| 170 | } | 196 | } |
| 171 | 197 | ||
| 172 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | 198 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, |
| 173 | u64 ip, char level, char *bf, size_t size, | 199 | u64 ip, char level, char *bf, size_t size, |
| 174 | unsigned int width __maybe_unused) | 200 | unsigned int width) |
| 175 | { | 201 | { |
| 176 | size_t ret = 0; | 202 | size_t ret = 0; |
| 177 | 203 | ||
| @@ -197,43 +223,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | |||
| 197 | return ret; | 223 | return ret; |
| 198 | } | 224 | } |
| 199 | 225 | ||
| 200 | |||
| 201 | struct sort_entry sort_dso = { | ||
| 202 | .se_header = "Shared Object", | ||
| 203 | .se_cmp = sort__dso_cmp, | ||
| 204 | .se_snprintf = hist_entry__dso_snprintf, | ||
| 205 | .se_width_idx = HISTC_DSO, | ||
| 206 | }; | ||
| 207 | |||
| 208 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | 226 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, |
| 209 | size_t size, | 227 | size_t size, unsigned int width) |
| 210 | unsigned int width __maybe_unused) | ||
| 211 | { | 228 | { |
| 212 | return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, | 229 | return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, |
| 213 | self->level, bf, size, width); | 230 | self->level, bf, size, width); |
| 214 | } | 231 | } |
| 215 | 232 | ||
| 216 | /* --sort symbol */ | ||
| 217 | static int64_t | ||
| 218 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | ||
| 219 | { | ||
| 220 | u64 ip_l, ip_r; | ||
| 221 | |||
| 222 | if (!left->ms.sym && !right->ms.sym) | ||
| 223 | return right->level - left->level; | ||
| 224 | |||
| 225 | if (!left->ms.sym || !right->ms.sym) | ||
| 226 | return cmp_null(left->ms.sym, right->ms.sym); | ||
| 227 | |||
| 228 | if (left->ms.sym == right->ms.sym) | ||
| 229 | return 0; | ||
| 230 | |||
| 231 | ip_l = left->ms.sym->start; | ||
| 232 | ip_r = right->ms.sym->start; | ||
| 233 | |||
| 234 | return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); | ||
| 235 | } | ||
| 236 | |||
| 237 | struct sort_entry sort_sym = { | 233 | struct sort_entry sort_sym = { |
| 238 | .se_header = "Symbol", | 234 | .se_header = "Symbol", |
| 239 | .se_cmp = sort__sym_cmp, | 235 | .se_cmp = sort__sym_cmp, |
| @@ -335,7 +331,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 335 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, | 331 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, |
| 336 | size_t size, unsigned int width) | 332 | size_t size, unsigned int width) |
| 337 | { | 333 | { |
| 338 | return repsep_snprintf(bf, size, "%-*d", width, self->cpu); | 334 | return repsep_snprintf(bf, size, "%*d", width, self->cpu); |
| 339 | } | 335 | } |
| 340 | 336 | ||
| 341 | struct sort_entry sort_cpu = { | 337 | struct sort_entry sort_cpu = { |
| @@ -345,6 +341,8 @@ struct sort_entry sort_cpu = { | |||
| 345 | .se_width_idx = HISTC_CPU, | 341 | .se_width_idx = HISTC_CPU, |
| 346 | }; | 342 | }; |
| 347 | 343 | ||
| 344 | /* sort keys for branch stacks */ | ||
| 345 | |||
| 348 | static int64_t | 346 | static int64_t |
| 349 | sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) | 347 | sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) |
| 350 | { | 348 | { |
| @@ -359,13 +357,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, | |||
| 359 | bf, size, width); | 357 | bf, size, width); |
| 360 | } | 358 | } |
| 361 | 359 | ||
| 362 | struct sort_entry sort_dso_from = { | ||
| 363 | .se_header = "Source Shared Object", | ||
| 364 | .se_cmp = sort__dso_from_cmp, | ||
| 365 | .se_snprintf = hist_entry__dso_from_snprintf, | ||
| 366 | .se_width_idx = HISTC_DSO_FROM, | ||
| 367 | }; | ||
| 368 | |||
| 369 | static int64_t | 360 | static int64_t |
| 370 | sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) | 361 | sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) |
| 371 | { | 362 | { |
| @@ -406,8 +397,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 406 | } | 397 | } |
| 407 | 398 | ||
| 408 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, | 399 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, |
| 409 | size_t size, | 400 | size_t size, unsigned int width) |
| 410 | unsigned int width __maybe_unused) | ||
| 411 | { | 401 | { |
| 412 | struct addr_map_symbol *from = &self->branch_info->from; | 402 | struct addr_map_symbol *from = &self->branch_info->from; |
| 413 | return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, | 403 | return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, |
| @@ -416,8 +406,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, | |||
| 416 | } | 406 | } |
| 417 | 407 | ||
| 418 | static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, | 408 | static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, |
| 419 | size_t size, | 409 | size_t size, unsigned int width) |
| 420 | unsigned int width __maybe_unused) | ||
| 421 | { | 410 | { |
| 422 | struct addr_map_symbol *to = &self->branch_info->to; | 411 | struct addr_map_symbol *to = &self->branch_info->to; |
| 423 | return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, | 412 | return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, |
| @@ -425,6 +414,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, | |||
| 425 | 414 | ||
| 426 | } | 415 | } |
| 427 | 416 | ||
| 417 | struct sort_entry sort_dso_from = { | ||
| 418 | .se_header = "Source Shared Object", | ||
| 419 | .se_cmp = sort__dso_from_cmp, | ||
| 420 | .se_snprintf = hist_entry__dso_from_snprintf, | ||
| 421 | .se_width_idx = HISTC_DSO_FROM, | ||
| 422 | }; | ||
| 423 | |||
| 428 | struct sort_entry sort_dso_to = { | 424 | struct sort_entry sort_dso_to = { |
| 429 | .se_header = "Target Shared Object", | 425 | .se_header = "Target Shared Object", |
| 430 | .se_cmp = sort__dso_to_cmp, | 426 | .se_cmp = sort__dso_to_cmp, |
| @@ -484,30 +480,40 @@ struct sort_dimension { | |||
| 484 | 480 | ||
| 485 | #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } | 481 | #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } |
| 486 | 482 | ||
| 487 | static struct sort_dimension sort_dimensions[] = { | 483 | static struct sort_dimension common_sort_dimensions[] = { |
| 488 | DIM(SORT_PID, "pid", sort_thread), | 484 | DIM(SORT_PID, "pid", sort_thread), |
| 489 | DIM(SORT_COMM, "comm", sort_comm), | 485 | DIM(SORT_COMM, "comm", sort_comm), |
| 490 | DIM(SORT_DSO, "dso", sort_dso), | 486 | DIM(SORT_DSO, "dso", sort_dso), |
| 491 | DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), | ||
| 492 | DIM(SORT_DSO_TO, "dso_to", sort_dso_to), | ||
| 493 | DIM(SORT_SYM, "symbol", sort_sym), | 487 | DIM(SORT_SYM, "symbol", sort_sym), |
| 494 | DIM(SORT_SYM_TO, "symbol_from", sort_sym_from), | ||
| 495 | DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to), | ||
| 496 | DIM(SORT_PARENT, "parent", sort_parent), | 488 | DIM(SORT_PARENT, "parent", sort_parent), |
| 497 | DIM(SORT_CPU, "cpu", sort_cpu), | 489 | DIM(SORT_CPU, "cpu", sort_cpu), |
| 498 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), | ||
| 499 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | 490 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
| 500 | }; | 491 | }; |
| 501 | 492 | ||
| 493 | #undef DIM | ||
| 494 | |||
| 495 | #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } | ||
| 496 | |||
| 497 | static struct sort_dimension bstack_sort_dimensions[] = { | ||
| 498 | DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), | ||
| 499 | DIM(SORT_DSO_TO, "dso_to", sort_dso_to), | ||
| 500 | DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), | ||
| 501 | DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), | ||
| 502 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), | ||
| 503 | }; | ||
| 504 | |||
| 505 | #undef DIM | ||
| 506 | |||
| 502 | int sort_dimension__add(const char *tok) | 507 | int sort_dimension__add(const char *tok) |
| 503 | { | 508 | { |
| 504 | unsigned int i; | 509 | unsigned int i; |
| 505 | 510 | ||
| 506 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 511 | for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { |
| 507 | struct sort_dimension *sd = &sort_dimensions[i]; | 512 | struct sort_dimension *sd = &common_sort_dimensions[i]; |
| 508 | 513 | ||
| 509 | if (strncasecmp(tok, sd->name, strlen(tok))) | 514 | if (strncasecmp(tok, sd->name, strlen(tok))) |
| 510 | continue; | 515 | continue; |
| 516 | |||
| 511 | if (sd->entry == &sort_parent) { | 517 | if (sd->entry == &sort_parent) { |
| 512 | int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); | 518 | int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); |
| 513 | if (ret) { | 519 | if (ret) { |
| @@ -518,9 +524,7 @@ int sort_dimension__add(const char *tok) | |||
| 518 | return -EINVAL; | 524 | return -EINVAL; |
| 519 | } | 525 | } |
| 520 | sort__has_parent = 1; | 526 | sort__has_parent = 1; |
| 521 | } else if (sd->entry == &sort_sym || | 527 | } else if (sd->entry == &sort_sym) { |
| 522 | sd->entry == &sort_sym_from || | ||
| 523 | sd->entry == &sort_sym_to) { | ||
| 524 | sort__has_sym = 1; | 528 | sort__has_sym = 1; |
| 525 | } | 529 | } |
| 526 | 530 | ||
| @@ -530,36 +534,42 @@ int sort_dimension__add(const char *tok) | |||
| 530 | if (sd->entry->se_collapse) | 534 | if (sd->entry->se_collapse) |
| 531 | sort__need_collapse = 1; | 535 | sort__need_collapse = 1; |
| 532 | 536 | ||
| 533 | if (list_empty(&hist_entry__sort_list)) { | 537 | if (list_empty(&hist_entry__sort_list)) |
| 534 | if (!strcmp(sd->name, "pid")) | 538 | sort__first_dimension = i; |
| 535 | sort__first_dimension = SORT_PID; | ||
| 536 | else if (!strcmp(sd->name, "comm")) | ||
| 537 | sort__first_dimension = SORT_COMM; | ||
| 538 | else if (!strcmp(sd->name, "dso")) | ||
| 539 | sort__first_dimension = SORT_DSO; | ||
| 540 | else if (!strcmp(sd->name, "symbol")) | ||
| 541 | sort__first_dimension = SORT_SYM; | ||
| 542 | else if (!strcmp(sd->name, "parent")) | ||
| 543 | sort__first_dimension = SORT_PARENT; | ||
| 544 | else if (!strcmp(sd->name, "cpu")) | ||
| 545 | sort__first_dimension = SORT_CPU; | ||
| 546 | else if (!strcmp(sd->name, "symbol_from")) | ||
| 547 | sort__first_dimension = SORT_SYM_FROM; | ||
| 548 | else if (!strcmp(sd->name, "symbol_to")) | ||
| 549 | sort__first_dimension = SORT_SYM_TO; | ||
| 550 | else if (!strcmp(sd->name, "dso_from")) | ||
| 551 | sort__first_dimension = SORT_DSO_FROM; | ||
| 552 | else if (!strcmp(sd->name, "dso_to")) | ||
| 553 | sort__first_dimension = SORT_DSO_TO; | ||
| 554 | else if (!strcmp(sd->name, "mispredict")) | ||
| 555 | sort__first_dimension = SORT_MISPREDICT; | ||
| 556 | } | ||
| 557 | 539 | ||
| 558 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | 540 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); |
| 559 | sd->taken = 1; | 541 | sd->taken = 1; |
| 560 | 542 | ||
| 561 | return 0; | 543 | return 0; |
| 562 | } | 544 | } |
| 545 | |||
| 546 | for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { | ||
| 547 | struct sort_dimension *sd = &bstack_sort_dimensions[i]; | ||
| 548 | |||
| 549 | if (strncasecmp(tok, sd->name, strlen(tok))) | ||
| 550 | continue; | ||
| 551 | |||
| 552 | if (sort__branch_mode != 1) | ||
| 553 | return -EINVAL; | ||
| 554 | |||
| 555 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) | ||
| 556 | sort__has_sym = 1; | ||
| 557 | |||
| 558 | if (sd->taken) | ||
| 559 | return 0; | ||
| 560 | |||
| 561 | if (sd->entry->se_collapse) | ||
| 562 | sort__need_collapse = 1; | ||
| 563 | |||
| 564 | if (list_empty(&hist_entry__sort_list)) | ||
| 565 | sort__first_dimension = i + __SORT_BRANCH_STACK; | ||
| 566 | |||
| 567 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | ||
| 568 | sd->taken = 1; | ||
| 569 | |||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | |||
| 563 | return -ESRCH; | 573 | return -ESRCH; |
| 564 | } | 574 | } |
| 565 | 575 | ||
| @@ -569,7 +579,11 @@ void setup_sorting(const char * const usagestr[], const struct option *opts) | |||
| 569 | 579 | ||
| 570 | for (tok = strtok_r(str, ", ", &tmp); | 580 | for (tok = strtok_r(str, ", ", &tmp); |
| 571 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 581 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
| 572 | if (sort_dimension__add(tok) < 0) { | 582 | int ret = sort_dimension__add(tok); |
| 583 | if (ret == -EINVAL) { | ||
| 584 | error("Invalid --sort key: `%s'", tok); | ||
| 585 | usage_with_options(usagestr, opts); | ||
| 586 | } else if (ret == -ESRCH) { | ||
| 573 | error("Unknown --sort key: `%s'", tok); | 587 | error("Unknown --sort key: `%s'", tok); |
| 574 | usage_with_options(usagestr, opts); | 588 | usage_with_options(usagestr, opts); |
| 575 | } | 589 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index a1c0d56b6885..e994ad3e9897 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -122,18 +122,22 @@ static inline void hist_entry__add_pair(struct hist_entry *he, | |||
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | enum sort_type { | 124 | enum sort_type { |
| 125 | /* common sort keys */ | ||
| 125 | SORT_PID, | 126 | SORT_PID, |
| 126 | SORT_COMM, | 127 | SORT_COMM, |
| 127 | SORT_DSO, | 128 | SORT_DSO, |
| 128 | SORT_SYM, | 129 | SORT_SYM, |
| 129 | SORT_PARENT, | 130 | SORT_PARENT, |
| 130 | SORT_CPU, | 131 | SORT_CPU, |
| 131 | SORT_DSO_FROM, | 132 | SORT_SRCLINE, |
| 133 | |||
| 134 | /* branch stack specific sort keys */ | ||
| 135 | __SORT_BRANCH_STACK, | ||
| 136 | SORT_DSO_FROM = __SORT_BRANCH_STACK, | ||
| 132 | SORT_DSO_TO, | 137 | SORT_DSO_TO, |
| 133 | SORT_SYM_FROM, | 138 | SORT_SYM_FROM, |
| 134 | SORT_SYM_TO, | 139 | SORT_SYM_TO, |
| 135 | SORT_MISPREDICT, | 140 | SORT_MISPREDICT, |
| 136 | SORT_SRCLINE, | ||
| 137 | }; | 141 | }; |
| 138 | 142 | ||
| 139 | /* | 143 | /* |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 346707df04b9..29c7b2cb2521 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
| @@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to) | |||
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | /** | 334 | /** |
| 335 | * ltrim - Removes leading whitespace from @s. | ||
| 336 | * @s: The string to be stripped. | ||
| 337 | * | ||
| 338 | * Return pointer to the first non-whitespace character in @s. | ||
| 339 | */ | ||
| 340 | char *ltrim(char *s) | ||
| 341 | { | ||
| 342 | int len = strlen(s); | ||
| 343 | |||
| 344 | while (len && isspace(*s)) { | ||
| 345 | len--; | ||
| 346 | s++; | ||
| 347 | } | ||
| 348 | |||
| 349 | return s; | ||
| 350 | } | ||
| 351 | |||
| 352 | /** | ||
| 335 | * rtrim - Removes trailing whitespace from @s. | 353 | * rtrim - Removes trailing whitespace from @s. |
| 336 | * @s: The string to be stripped. | 354 | * @s: The string to be stripped. |
| 337 | * | 355 | * |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index f63557b59c06..54efcb5659ac 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | #include <libelf.h> | ||
| 2 | #include <gelf.h> | ||
| 3 | #include <elf.h> | ||
| 4 | #include <fcntl.h> | 1 | #include <fcntl.h> |
| 5 | #include <stdio.h> | 2 | #include <stdio.h> |
| 6 | #include <errno.h> | 3 | #include <errno.h> |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 259f8f2ea9c9..a7390cde63bc 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include "symbol.h" | 1 | #include "symbol.h" |
| 2 | 2 | ||
| 3 | #include <elf.h> | ||
| 4 | #include <stdio.h> | 3 | #include <stdio.h> |
| 5 | #include <fcntl.h> | 4 | #include <fcntl.h> |
| 6 | #include <string.h> | 5 | #include <string.h> |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 2960284d6ae1..e6432d85b43d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -768,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
| 768 | else | 768 | else |
| 769 | machine = NULL; | 769 | machine = NULL; |
| 770 | 770 | ||
| 771 | name = malloc(PATH_MAX); | ||
| 772 | if (!name) | ||
| 773 | return -1; | ||
| 774 | |||
| 775 | dso->adjust_symbols = 0; | 771 | dso->adjust_symbols = 0; |
| 776 | 772 | ||
| 777 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 773 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
| @@ -795,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
| 795 | if (machine) | 791 | if (machine) |
| 796 | root_dir = machine->root_dir; | 792 | root_dir = machine->root_dir; |
| 797 | 793 | ||
| 794 | name = malloc(PATH_MAX); | ||
| 795 | if (!name) | ||
| 796 | return -1; | ||
| 797 | |||
| 798 | /* Iterate over candidate debug images. | 798 | /* Iterate over candidate debug images. |
| 799 | * Keep track of "interesting" ones (those which have a symtab, dynsym, | 799 | * Keep track of "interesting" ones (those which have a symtab, dynsym, |
| 800 | * and/or opd section) for processing. | 800 | * and/or opd section) for processing. |
| @@ -923,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
| 923 | filename = dso__build_id_filename(dso, NULL, 0); | 923 | filename = dso__build_id_filename(dso, NULL, 0); |
| 924 | if (filename != NULL) { | 924 | if (filename != NULL) { |
| 925 | err = dso__load_vmlinux(dso, map, filename, filter); | 925 | err = dso__load_vmlinux(dso, map, filename, filter); |
| 926 | if (err > 0) | 926 | if (err > 0) { |
| 927 | dso->lname_alloc = 1; | ||
| 927 | goto out; | 928 | goto out; |
| 929 | } | ||
| 928 | free(filename); | 930 | free(filename); |
| 929 | } | 931 | } |
| 930 | 932 | ||
| @@ -932,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
| 932 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); | 934 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); |
| 933 | if (err > 0) { | 935 | if (err > 0) { |
| 934 | dso__set_long_name(dso, strdup(vmlinux_path[i])); | 936 | dso__set_long_name(dso, strdup(vmlinux_path[i])); |
| 937 | dso->lname_alloc = 1; | ||
| 935 | break; | 938 | break; |
| 936 | } | 939 | } |
| 937 | } | 940 | } |
| @@ -971,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
| 971 | if (err > 0) { | 974 | if (err > 0) { |
| 972 | dso__set_long_name(dso, | 975 | dso__set_long_name(dso, |
| 973 | strdup(symbol_conf.vmlinux_name)); | 976 | strdup(symbol_conf.vmlinux_name)); |
| 977 | dso->lname_alloc = 1; | ||
| 974 | goto out_fixup; | 978 | goto out_fixup; |
| 975 | } | 979 | } |
| 976 | return err; | 980 | return err; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ec7b2405c377..d97377ac2f16 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -16,8 +16,8 @@ | |||
| 16 | #ifdef LIBELF_SUPPORT | 16 | #ifdef LIBELF_SUPPORT |
| 17 | #include <libelf.h> | 17 | #include <libelf.h> |
| 18 | #include <gelf.h> | 18 | #include <gelf.h> |
| 19 | #include <elf.h> | ||
| 20 | #endif | 19 | #endif |
| 20 | #include <elf.h> | ||
| 21 | 21 | ||
| 22 | #include "dso.h" | 22 | #include "dso.h" |
| 23 | 23 | ||
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c index 48c6902e749f..f71e9eafe15a 100644 --- a/tools/perf/util/sysfs.c +++ b/tools/perf/util/sysfs.c | |||
| @@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = { | |||
| 8 | }; | 8 | }; |
| 9 | 9 | ||
| 10 | static int sysfs_found; | 10 | static int sysfs_found; |
| 11 | char sysfs_mountpoint[PATH_MAX]; | 11 | char sysfs_mountpoint[PATH_MAX + 1]; |
| 12 | 12 | ||
| 13 | static int sysfs_valid_mountpoint(const char *sysfs) | 13 | static int sysfs_valid_mountpoint(const char *sysfs) |
| 14 | { | 14 | { |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 927c229c2d9a..7ebf357dc9e1 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
| @@ -29,8 +29,6 @@ struct perf_top { | |||
| 29 | bool sort_has_symbols; | 29 | bool sort_has_symbols; |
| 30 | bool kptr_restrict_warned; | 30 | bool kptr_restrict_warned; |
| 31 | bool vmlinux_warned; | 31 | bool vmlinux_warned; |
| 32 | bool sample_id_all_missing; | ||
| 33 | bool exclude_guest_missing; | ||
| 34 | bool dump_symtab; | 32 | bool dump_symtab; |
| 35 | struct hist_entry *sym_filter_entry; | 33 | struct hist_entry *sym_filter_entry; |
| 36 | struct perf_evsel *sym_evsel; | 34 | struct perf_evsel *sym_evsel; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5906e8426cc7..805d1f52c5b4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | */ | 12 | */ |
| 13 | unsigned int page_size; | 13 | unsigned int page_size; |
| 14 | 14 | ||
| 15 | bool test_attr__enabled; | ||
| 16 | |||
| 15 | bool perf_host = true; | 17 | bool perf_host = true; |
| 16 | bool perf_guest = false; | 18 | bool perf_guest = false; |
| 17 | 19 | ||
| @@ -218,3 +220,25 @@ void dump_stack(void) | |||
| 218 | #else | 220 | #else |
| 219 | void dump_stack(void) {} | 221 | void dump_stack(void) {} |
| 220 | #endif | 222 | #endif |
| 223 | |||
| 224 | void get_term_dimensions(struct winsize *ws) | ||
| 225 | { | ||
| 226 | char *s = getenv("LINES"); | ||
| 227 | |||
| 228 | if (s != NULL) { | ||
| 229 | ws->ws_row = atoi(s); | ||
| 230 | s = getenv("COLUMNS"); | ||
| 231 | if (s != NULL) { | ||
| 232 | ws->ws_col = atoi(s); | ||
| 233 | if (ws->ws_row && ws->ws_col) | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | #ifdef TIOCGWINSZ | ||
| 238 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
| 239 | ws->ws_row && ws->ws_col) | ||
| 240 | return; | ||
| 241 | #endif | ||
| 242 | ws->ws_row = 25; | ||
| 243 | ws->ws_col = 80; | ||
| 244 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c2330918110c..09b4c26b71aa 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n) | |||
| 265 | size_t hex_width(u64 v); | 265 | size_t hex_width(u64 v); |
| 266 | int hex2u64(const char *ptr, u64 *val); | 266 | int hex2u64(const char *ptr, u64 *val); |
| 267 | 267 | ||
| 268 | char *ltrim(char *s); | ||
| 268 | char *rtrim(char *s); | 269 | char *rtrim(char *s); |
| 269 | 270 | ||
| 270 | void dump_stack(void); | 271 | void dump_stack(void); |
| 271 | 272 | ||
| 272 | extern unsigned int page_size; | 273 | extern unsigned int page_size; |
| 273 | 274 | ||
| 275 | struct winsize; | ||
| 276 | void get_term_dimensions(struct winsize *ws); | ||
| 277 | |||
| 274 | #endif | 278 | #endif |
