diff options
author | Jens Axboe <axboe@kernel.dk> | 2011-10-19 08:30:42 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2011-10-19 08:30:42 -0400 |
commit | 5c04b426f2e8b46cfc7969a35b2631063a3c646c (patch) | |
tree | 2d27d9f5d2fe5d5e8fbc01a467ec58bcb50235c1 /tools | |
parent | 499337bb6511e665a236a6a947f819d98ea340c6 (diff) | |
parent | 899e3ee404961a90b828ad527573aaaac39f0ab1 (diff) |
Merge branch 'v3.1-rc10' into for-3.2/core
Conflicts:
block/blk-core.c
include/linux/blkdev.h
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'tools')
52 files changed, 1185 insertions, 555 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 56d62d3fb167..e9d5c271db69 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -30,6 +30,8 @@ endif | |||
30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
31 | # | 31 | # |
32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. | 32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. |
33 | # | ||
34 | # Define WERROR=0 to disable treating any warnings as errors. | ||
33 | 35 | ||
34 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 36 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
35 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 37 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
@@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64) | |||
63 | endif | 65 | endif |
64 | endif | 66 | endif |
65 | 67 | ||
68 | # Treat warnings as errors unless directed not to | ||
69 | ifneq ($(WERROR),0) | ||
70 | CFLAGS_WERROR := -Werror | ||
71 | endif | ||
72 | |||
66 | # | 73 | # |
67 | # Include saner warnings here, which can catch bugs: | 74 | # Include saner warnings here, which can catch bugs: |
68 | # | 75 | # |
@@ -95,7 +102,7 @@ ifndef PERF_DEBUG | |||
95 | CFLAGS_OPTIMIZE = -O6 | 102 | CFLAGS_OPTIMIZE = -O6 |
96 | endif | 103 | endif |
97 | 104 | ||
98 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 105 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
99 | EXTLIBS = -lpthread -lrt -lelf -lm | 106 | EXTLIBS = -lpthread -lrt -lelf -lm |
100 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | 107 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 |
101 | ALL_LDFLAGS = $(LDFLAGS) | 108 | ALL_LDFLAGS = $(LDFLAGS) |
@@ -181,9 +188,9 @@ strip-libs = $(filter-out -l%,$(1)) | |||
181 | 188 | ||
182 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) | 189 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) |
183 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 190 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
184 | --quiet build_ext \ | 191 | --quiet build_ext; \ |
185 | --build-lib='$(OUTPUT)python' \ | 192 | mkdir -p $(OUTPUT)python && \ |
186 | --build-temp='$(OUTPUT)python/temp' | 193 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
187 | # | 194 | # |
188 | # No Perl scripts right now: | 195 | # No Perl scripts right now: |
189 | # | 196 | # |
@@ -509,9 +516,13 @@ else | |||
509 | 516 | ||
510 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 517 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
511 | 518 | ||
512 | python-clean := $(PYTHON_WORD) util/setup.py clean \ | 519 | # python extension build directories |
513 | --build-lib='$(OUTPUT)python' \ | 520 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
514 | --build-temp='$(OUTPUT)python/temp' | 521 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
522 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
523 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
524 | |||
525 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
515 | 526 | ||
516 | ifdef NO_LIBPYTHON | 527 | ifdef NO_LIBPYTHON |
517 | $(call disable-python) | 528 | $(call disable-python) |
@@ -868,6 +879,9 @@ install: all | |||
868 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' | 879 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' |
869 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 880 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
870 | 881 | ||
882 | install-python_ext: | ||
883 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | ||
884 | |||
871 | install-doc: | 885 | install-doc: |
872 | $(MAKE) -C Documentation install | 886 | $(MAKE) -C Documentation install |
873 | 887 | ||
@@ -895,7 +909,7 @@ quick-install-html: | |||
895 | ### Cleaning rules | 909 | ### Cleaning rules |
896 | 910 | ||
897 | clean: | 911 | clean: |
898 | $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} | 912 | $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) |
899 | $(RM) $(ALL_PROGRAMS) perf | 913 | $(RM) $(ALL_PROGRAMS) perf |
900 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* | 914 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* |
901 | $(MAKE) -C Documentation/ clean | 915 | $(MAKE) -C Documentation/ clean |
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index fff6450c8c99..e8d5c551c69c 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c | |||
@@ -8,7 +8,10 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <stdlib.h> | ||
12 | #ifndef __UCLIBC__ | ||
11 | #include <libio.h> | 13 | #include <libio.h> |
14 | #endif | ||
12 | #include <dwarf-regs.h> | 15 | #include <dwarf-regs.h> |
13 | 16 | ||
14 | struct pt_regs_dwarfnum { | 17 | struct pt_regs_dwarfnum { |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 9ac05aafd9b2..899080ace267 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -942,10 +942,10 @@ static const char *record_args[] = { | |||
942 | "-f", | 942 | "-f", |
943 | "-m", "1024", | 943 | "-m", "1024", |
944 | "-c", "1", | 944 | "-c", "1", |
945 | "-e", "lock:lock_acquire:r", | 945 | "-e", "lock:lock_acquire", |
946 | "-e", "lock:lock_acquired:r", | 946 | "-e", "lock:lock_acquired", |
947 | "-e", "lock:lock_contended:r", | 947 | "-e", "lock:lock_contended", |
948 | "-e", "lock:lock_release:r", | 948 | "-e", "lock:lock_release", |
949 | }; | 949 | }; |
950 | 950 | ||
951 | static int __cmd_record(int argc, const char **argv) | 951 | static int __cmd_record(int argc, const char **argv) |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 5f2a5c7046df..710ae3d0a489 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used, | |||
134 | { | 134 | { |
135 | int ret = 0; | 135 | int ret = 0; |
136 | 136 | ||
137 | if (str) | 137 | if (!str) |
138 | ret = parse_line_range_desc(str, ¶ms.line_range); | 138 | return 0; |
139 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 139 | |
140 | if (params.show_lines) { | ||
141 | pr_warning("Warning: more than one --line options are" | ||
142 | " detected. Only the first one is valid.\n"); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
140 | params.show_lines = true; | 146 | params.show_lines = true; |
147 | ret = parse_line_range_desc(str, ¶ms.line_range); | ||
148 | INIT_LIST_HEAD(¶ms.line_range.line_list); | ||
141 | 149 | ||
142 | return ret; | 150 | return ret; |
143 | } | 151 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 80dc5b790e47..f4c3fbee4bad 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #include <sched.h> | 30 | #include <sched.h> |
31 | #include <sys/mman.h> | 31 | #include <sys/mman.h> |
32 | 32 | ||
33 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
34 | |||
35 | enum write_mode_t { | 33 | enum write_mode_t { |
36 | WRITE_FORCE, | 34 | WRITE_FORCE, |
37 | WRITE_APPEND | 35 | WRITE_APPEND |
@@ -47,7 +45,7 @@ static int freq = 1000; | |||
47 | static int output; | 45 | static int output; |
48 | static int pipe_output = 0; | 46 | static int pipe_output = 0; |
49 | static const char *output_name = NULL; | 47 | static const char *output_name = NULL; |
50 | static int group = 0; | 48 | static bool group = false; |
51 | static int realtime_prio = 0; | 49 | static int realtime_prio = 0; |
52 | static bool nodelay = false; | 50 | static bool nodelay = false; |
53 | static bool raw_samples = false; | 51 | static bool raw_samples = false; |
@@ -163,6 +161,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | |||
163 | struct perf_event_attr *attr = &evsel->attr; | 161 | struct perf_event_attr *attr = &evsel->attr; |
164 | int track = !evsel->idx; /* only the first counter needs these */ | 162 | int track = !evsel->idx; /* only the first counter needs these */ |
165 | 163 | ||
164 | attr->disabled = 1; | ||
166 | attr->inherit = !no_inherit; | 165 | attr->inherit = !no_inherit; |
167 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 166 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
168 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 167 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
@@ -438,7 +437,6 @@ static void mmap_read_all(void) | |||
438 | 437 | ||
439 | static int __cmd_record(int argc, const char **argv) | 438 | static int __cmd_record(int argc, const char **argv) |
440 | { | 439 | { |
441 | int i; | ||
442 | struct stat st; | 440 | struct stat st; |
443 | int flags; | 441 | int flags; |
444 | int err; | 442 | int err; |
@@ -674,6 +672,8 @@ static int __cmd_record(int argc, const char **argv) | |||
674 | } | 672 | } |
675 | } | 673 | } |
676 | 674 | ||
675 | perf_evlist__enable(evsel_list); | ||
676 | |||
677 | /* | 677 | /* |
678 | * Let the child rip | 678 | * Let the child rip |
679 | */ | 679 | */ |
@@ -682,7 +682,6 @@ static int __cmd_record(int argc, const char **argv) | |||
682 | 682 | ||
683 | for (;;) { | 683 | for (;;) { |
684 | int hits = samples; | 684 | int hits = samples; |
685 | int thread; | ||
686 | 685 | ||
687 | mmap_read_all(); | 686 | mmap_read_all(); |
688 | 687 | ||
@@ -693,19 +692,8 @@ static int __cmd_record(int argc, const char **argv) | |||
693 | waking++; | 692 | waking++; |
694 | } | 693 | } |
695 | 694 | ||
696 | if (done) { | 695 | if (done) |
697 | for (i = 0; i < evsel_list->cpus->nr; i++) { | 696 | perf_evlist__disable(evsel_list); |
698 | struct perf_evsel *pos; | ||
699 | |||
700 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
701 | for (thread = 0; | ||
702 | thread < evsel_list->threads->nr; | ||
703 | thread++) | ||
704 | ioctl(FD(pos, i, thread), | ||
705 | PERF_EVENT_IOC_DISABLE); | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | } | 697 | } |
710 | 698 | ||
711 | if (quiet || signr == SIGUSR1) | 699 | if (quiet || signr == SIGUSR1) |
@@ -768,6 +756,8 @@ const struct option record_options[] = { | |||
768 | "child tasks do not inherit counters"), | 756 | "child tasks do not inherit counters"), |
769 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), | 757 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), |
770 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), | 758 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
759 | OPT_BOOLEAN(0, "group", &group, | ||
760 | "put the counters into a counter group"), | ||
771 | OPT_BOOLEAN('g', "call-graph", &call_graph, | 761 | OPT_BOOLEAN('g', "call-graph", &call_graph, |
772 | "do call-graph (stack chain/backtrace) recording"), | 762 | "do call-graph (stack chain/backtrace) recording"), |
773 | OPT_INCR('v', "verbose", &verbose, | 763 | OPT_INCR('v', "verbose", &verbose, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f854efda7686..d7ff277bdb78 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -162,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self) | |||
162 | { | 162 | { |
163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
164 | if (sort__has_parent) { | 164 | if (sort__has_parent) { |
165 | fprintf(stderr, "selected --sort parent, but no" | 165 | ui__warning("Selected --sort parent, but no " |
166 | " callchain data. Did you call" | 166 | "callchain data. Did you call " |
167 | " perf record without -g?\n"); | 167 | "'perf record' without -g?\n"); |
168 | return -EINVAL; | 168 | return -EINVAL; |
169 | } | 169 | } |
170 | if (symbol_conf.use_callchain) { | 170 | if (symbol_conf.use_callchain) { |
171 | fprintf(stderr, "selected -g but no callchain data." | 171 | ui__warning("Selected -g but no callchain data. Did " |
172 | " Did you call perf record without" | 172 | "you call 'perf record' without -g?\n"); |
173 | " -g?\n"); | ||
174 | return -1; | 173 | return -1; |
175 | } | 174 | } |
176 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && | 175 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && |
177 | !symbol_conf.use_callchain) { | 176 | !symbol_conf.use_callchain) { |
178 | symbol_conf.use_callchain = true; | 177 | symbol_conf.use_callchain = true; |
179 | if (callchain_register_param(&callchain_param) < 0) { | 178 | if (callchain_register_param(&callchain_param) < 0) { |
180 | fprintf(stderr, "Can't register callchain" | 179 | ui__warning("Can't register callchain " |
181 | " params\n"); | 180 | "params.\n"); |
182 | return -EINVAL; | 181 | return -EINVAL; |
183 | } | 182 | } |
184 | } | 183 | } |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index dcfe8873c9a1..5177964943e7 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = { | |||
1637 | .ordered_samples = true, | 1637 | .ordered_samples = true, |
1638 | }; | 1638 | }; |
1639 | 1639 | ||
1640 | static int read_events(void) | 1640 | static void read_events(bool destroy, struct perf_session **psession) |
1641 | { | 1641 | { |
1642 | int err = -EINVAL; | 1642 | int err = -EINVAL; |
1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
1644 | 0, false, &event_ops); | 1644 | 0, false, &event_ops); |
1645 | if (session == NULL) | 1645 | if (session == NULL) |
1646 | return -ENOMEM; | 1646 | die("No Memory"); |
1647 | 1647 | ||
1648 | if (perf_session__has_traces(session, "record -R")) { | 1648 | if (perf_session__has_traces(session, "record -R")) { |
1649 | err = perf_session__process_events(session, &event_ops); | 1649 | err = perf_session__process_events(session, &event_ops); |
1650 | if (err) | ||
1651 | die("Failed to process events, error %d", err); | ||
1652 | |||
1650 | nr_events = session->hists.stats.nr_events[0]; | 1653 | nr_events = session->hists.stats.nr_events[0]; |
1651 | nr_lost_events = session->hists.stats.total_lost; | 1654 | nr_lost_events = session->hists.stats.total_lost; |
1652 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; | 1655 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; |
1653 | } | 1656 | } |
1654 | 1657 | ||
1655 | perf_session__delete(session); | 1658 | if (destroy) |
1656 | return err; | 1659 | perf_session__delete(session); |
1660 | |||
1661 | if (psession) | ||
1662 | *psession = session; | ||
1657 | } | 1663 | } |
1658 | 1664 | ||
1659 | static void print_bad_events(void) | 1665 | static void print_bad_events(void) |
@@ -1689,9 +1695,10 @@ static void print_bad_events(void) | |||
1689 | static void __cmd_lat(void) | 1695 | static void __cmd_lat(void) |
1690 | { | 1696 | { |
1691 | struct rb_node *next; | 1697 | struct rb_node *next; |
1698 | struct perf_session *session; | ||
1692 | 1699 | ||
1693 | setup_pager(); | 1700 | setup_pager(); |
1694 | read_events(); | 1701 | read_events(false, &session); |
1695 | sort_lat(); | 1702 | sort_lat(); |
1696 | 1703 | ||
1697 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); | 1704 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void) | |||
1717 | print_bad_events(); | 1724 | print_bad_events(); |
1718 | printf("\n"); | 1725 | printf("\n"); |
1719 | 1726 | ||
1727 | perf_session__delete(session); | ||
1720 | } | 1728 | } |
1721 | 1729 | ||
1722 | static struct trace_sched_handler map_ops = { | 1730 | static struct trace_sched_handler map_ops = { |
@@ -1731,7 +1739,7 @@ static void __cmd_map(void) | |||
1731 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1739 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
1732 | 1740 | ||
1733 | setup_pager(); | 1741 | setup_pager(); |
1734 | read_events(); | 1742 | read_events(true, NULL); |
1735 | print_bad_events(); | 1743 | print_bad_events(); |
1736 | } | 1744 | } |
1737 | 1745 | ||
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void) | |||
1744 | 1752 | ||
1745 | test_calibrations(); | 1753 | test_calibrations(); |
1746 | 1754 | ||
1747 | read_events(); | 1755 | read_events(true, NULL); |
1748 | 1756 | ||
1749 | printf("nr_run_events: %ld\n", nr_run_events); | 1757 | printf("nr_run_events: %ld\n", nr_run_events); |
1750 | printf("nr_sleep_events: %ld\n", nr_sleep_events); | 1758 | printf("nr_sleep_events: %ld\n", nr_sleep_events); |
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void) | |||
1769 | 1777 | ||
1770 | 1778 | ||
1771 | static const char * const sched_usage[] = { | 1779 | static const char * const sched_usage[] = { |
1772 | "perf sched [<options>] {record|latency|map|replay|trace}", | 1780 | "perf sched [<options>] {record|latency|map|replay|script}", |
1773 | NULL | 1781 | NULL |
1774 | }; | 1782 | }; |
1775 | 1783 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1ad04ce29c34..5deb17d9e795 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -193,6 +193,7 @@ static int big_num_opt = -1; | |||
193 | static const char *cpu_list; | 193 | static const char *cpu_list; |
194 | static const char *csv_sep = NULL; | 194 | static const char *csv_sep = NULL; |
195 | static bool csv_output = false; | 195 | static bool csv_output = false; |
196 | static bool group = false; | ||
196 | 197 | ||
197 | static volatile int done = 0; | 198 | static volatile int done = 0; |
198 | 199 | ||
@@ -280,14 +281,14 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
280 | attr->inherit = !no_inherit; | 281 | attr->inherit = !no_inherit; |
281 | 282 | ||
282 | if (system_wide) | 283 | if (system_wide) |
283 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); | 284 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group); |
284 | 285 | ||
285 | if (target_pid == -1 && target_tid == -1) { | 286 | if (target_pid == -1 && target_tid == -1) { |
286 | attr->disabled = 1; | 287 | attr->disabled = 1; |
287 | attr->enable_on_exec = 1; | 288 | attr->enable_on_exec = 1; |
288 | } | 289 | } |
289 | 290 | ||
290 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); | 291 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, group); |
291 | } | 292 | } |
292 | 293 | ||
293 | /* | 294 | /* |
@@ -1043,6 +1044,8 @@ static const struct option options[] = { | |||
1043 | "stat events on existing thread id"), | 1044 | "stat events on existing thread id"), |
1044 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1045 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1045 | "system-wide collection from all CPUs"), | 1046 | "system-wide collection from all CPUs"), |
1047 | OPT_BOOLEAN('g', "group", &group, | ||
1048 | "put the counters into a counter group"), | ||
1046 | OPT_BOOLEAN('c', "scale", &scale, | 1049 | OPT_BOOLEAN('c', "scale", &scale, |
1047 | "scale/normalize counters"), | 1050 | "scale/normalize counters"), |
1048 | OPT_INCR('v', "verbose", &verbose, | 1051 | OPT_INCR('v', "verbose", &verbose, |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 55f4c76f2821..efe696f936e2 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -561,7 +561,7 @@ static int test__basic_mmap(void) | |||
561 | } | 561 | } |
562 | 562 | ||
563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, | 563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, |
564 | false, &sample); | 564 | false, &sample, false); |
565 | if (err) { | 565 | if (err) { |
566 | pr_err("Can't parse sample, err = %d\n", err); | 566 | pr_err("Can't parse sample, err = %d\n", err); |
567 | goto out_munmap; | 567 | goto out_munmap; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a43433f08300..d28013b7d61c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme) | |||
191 | symbol__annotate_zero_histograms(sym); | 191 | symbol__annotate_zero_histograms(sym); |
192 | } | 192 | } |
193 | 193 | ||
194 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | 194 | static void record_precise_ip(struct sym_entry *syme, struct map *map, |
195 | int counter, u64 ip) | ||
195 | { | 196 | { |
196 | struct annotation *notes; | 197 | struct annotation *notes; |
197 | struct symbol *sym; | 198 | struct symbol *sym; |
@@ -205,8 +206,8 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | |||
205 | if (pthread_mutex_trylock(¬es->lock)) | 206 | if (pthread_mutex_trylock(¬es->lock)) |
206 | return; | 207 | return; |
207 | 208 | ||
208 | ip = syme->map->map_ip(syme->map, ip); | 209 | ip = map->map_ip(map, ip); |
209 | symbol__inc_addr_samples(sym, syme->map, counter, ip); | 210 | symbol__inc_addr_samples(sym, map, counter, ip); |
210 | 211 | ||
211 | pthread_mutex_unlock(¬es->lock); | 212 | pthread_mutex_unlock(¬es->lock); |
212 | } | 213 | } |
@@ -810,7 +811,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
810 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | 811 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); |
811 | assert(evsel != NULL); | 812 | assert(evsel != NULL); |
812 | syme->count[evsel->idx]++; | 813 | syme->count[evsel->idx]++; |
813 | record_precise_ip(syme, evsel->idx, ip); | 814 | record_precise_ip(syme, al.map, evsel->idx, ip); |
814 | pthread_mutex_lock(&top.active_symbols_lock); | 815 | pthread_mutex_lock(&top.active_symbols_lock); |
815 | if (list_empty(&syme->node) || !syme->node.next) { | 816 | if (list_empty(&syme->node) || !syme->node.next) { |
816 | static bool first = true; | 817 | static bool first = true; |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e02d78cae70f..fe02903f7d0f 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -399,7 +399,6 @@ static int perf_config_global(void) | |||
399 | int perf_config(config_fn_t fn, void *data) | 399 | int perf_config(config_fn_t fn, void *data) |
400 | { | 400 | { |
401 | int ret = 0, found = 0; | 401 | int ret = 0, found = 0; |
402 | char *repo_config = NULL; | ||
403 | const char *home = NULL; | 402 | const char *home = NULL; |
404 | 403 | ||
405 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ | 404 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ |
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data) | |||
414 | home = getenv("HOME"); | 413 | home = getenv("HOME"); |
415 | if (perf_config_global() && home) { | 414 | if (perf_config_global() && home) { |
416 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); | 415 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); |
417 | if (!access(user_config, R_OK)) { | 416 | struct stat st; |
418 | ret += perf_config_from_file(fn, user_config, data); | 417 | |
419 | found += 1; | 418 | if (user_config == NULL) { |
419 | warning("Not enough memory to process %s/.perfconfig, " | ||
420 | "ignoring it.", home); | ||
421 | goto out; | ||
420 | } | 422 | } |
421 | free(user_config); | ||
422 | } | ||
423 | 423 | ||
424 | repo_config = perf_pathdup("config"); | 424 | if (stat(user_config, &st) < 0) |
425 | if (!access(repo_config, R_OK)) { | 425 | goto out_free; |
426 | ret += perf_config_from_file(fn, repo_config, data); | 426 | |
427 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
428 | warning("File %s not owned by current user or root, " | ||
429 | "ignoring it.", user_config); | ||
430 | goto out_free; | ||
431 | } | ||
432 | |||
433 | if (!st.st_size) | ||
434 | goto out_free; | ||
435 | |||
436 | ret += perf_config_from_file(fn, user_config, data); | ||
427 | found += 1; | 437 | found += 1; |
438 | out_free: | ||
439 | free(user_config); | ||
428 | } | 440 | } |
429 | free(repo_config); | 441 | out: |
430 | if (found == 0) | 442 | if (found == 0) |
431 | return -1; | 443 | return -1; |
432 | return ret; | 444 | return ret; |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index fddf40f30d3e..ee51e9b4dc09 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, | |||
96 | return *lineno ?: -ENOENT; | 96 | return *lineno ?: -ENOENT; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); | ||
100 | |||
101 | /** | ||
102 | * cu_walk_functions_at - Walk on function DIEs at given address | ||
103 | * @cu_die: A CU DIE | ||
104 | * @addr: An address | ||
105 | * @callback: A callback which called with found DIEs | ||
106 | * @data: A user data | ||
107 | * | ||
108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs | ||
109 | * should be subprogram or inlined-subroutines. | ||
110 | */ | ||
111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
112 | int (*callback)(Dwarf_Die *, void *), void *data) | ||
113 | { | ||
114 | Dwarf_Die die_mem; | ||
115 | Dwarf_Die *sc_die; | ||
116 | int ret = -ENOENT; | ||
117 | |||
118 | /* Inlined function could be recursive. Trace it until fail */ | ||
119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); | ||
120 | sc_die != NULL; | ||
121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, | ||
122 | &die_mem)) { | ||
123 | ret = callback(sc_die, data); | ||
124 | if (ret) | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | return ret; | ||
129 | |||
130 | } | ||
131 | |||
99 | /** | 132 | /** |
100 | * die_compare_name - Compare diename and tname | 133 | * die_compare_name - Compare diename and tname |
101 | * @dw_die: a DIE | 134 | * @dw_die: a DIE |
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | |||
198 | return 0; | 231 | return 0; |
199 | } | 232 | } |
200 | 233 | ||
234 | /* Get attribute and translate it as a sdata */ | ||
235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
236 | Dwarf_Sword *result) | ||
237 | { | ||
238 | Dwarf_Attribute attr; | ||
239 | |||
240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
241 | dwarf_formsdata(&attr, result) != 0) | ||
242 | return -ENOENT; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
201 | /** | 247 | /** |
202 | * die_is_signed_type - Check whether a type DIE is signed or not | 248 | * die_is_signed_type - Check whether a type DIE is signed or not |
203 | * @tp_die: a DIE of a type | 249 | * @tp_die: a DIE of a type |
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | |||
250 | return 0; | 296 | return 0; |
251 | } | 297 | } |
252 | 298 | ||
299 | /* Get the call file index number in CU DIE */ | ||
300 | static int die_get_call_fileno(Dwarf_Die *in_die) | ||
301 | { | ||
302 | Dwarf_Sword idx; | ||
303 | |||
304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | ||
305 | return (int)idx; | ||
306 | else | ||
307 | return -ENOENT; | ||
308 | } | ||
309 | |||
310 | /* Get the declared file index number in CU DIE */ | ||
311 | static int die_get_decl_fileno(Dwarf_Die *pdie) | ||
312 | { | ||
313 | Dwarf_Sword idx; | ||
314 | |||
315 | if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0) | ||
316 | return (int)idx; | ||
317 | else | ||
318 | return -ENOENT; | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * die_get_call_file - Get callsite file name of inlined function instance | ||
323 | * @in_die: a DIE of an inlined function instance | ||
324 | * | ||
325 | * Get call-site file name of @in_die. This means from which file the inline | ||
326 | * function is called. | ||
327 | */ | ||
328 | const char *die_get_call_file(Dwarf_Die *in_die) | ||
329 | { | ||
330 | Dwarf_Die cu_die; | ||
331 | Dwarf_Files *files; | ||
332 | int idx; | ||
333 | |||
334 | idx = die_get_call_fileno(in_die); | ||
335 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | ||
336 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | ||
337 | return NULL; | ||
338 | |||
339 | return dwarf_filesrc(files, idx, NULL, NULL); | ||
340 | } | ||
341 | |||
342 | |||
253 | /** | 343 | /** |
254 | * die_find_child - Generic DIE search function in DIE tree | 344 | * die_find_child - Generic DIE search function in DIE tree |
255 | * @rt_die: a root DIE | 345 | * @rt_die: a root DIE |
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
374 | return die_mem; | 464 | return die_mem; |
375 | } | 465 | } |
376 | 466 | ||
467 | struct __instance_walk_param { | ||
468 | void *addr; | ||
469 | int (*callback)(Dwarf_Die *, void *); | ||
470 | void *data; | ||
471 | int retval; | ||
472 | }; | ||
473 | |||
474 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
475 | { | ||
476 | struct __instance_walk_param *iwp = data; | ||
477 | Dwarf_Attribute attr_mem; | ||
478 | Dwarf_Die origin_mem; | ||
479 | Dwarf_Attribute *attr; | ||
480 | Dwarf_Die *origin; | ||
481 | int tmp; | ||
482 | |||
483 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
484 | if (attr == NULL) | ||
485 | return DIE_FIND_CB_CONTINUE; | ||
486 | |||
487 | origin = dwarf_formref_die(attr, &origin_mem); | ||
488 | if (origin == NULL || origin->addr != iwp->addr) | ||
489 | return DIE_FIND_CB_CONTINUE; | ||
490 | |||
491 | /* Ignore redundant instances */ | ||
492 | if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { | ||
493 | dwarf_decl_line(origin, &tmp); | ||
494 | if (die_get_call_lineno(inst) == tmp) { | ||
495 | tmp = die_get_decl_fileno(origin); | ||
496 | if (die_get_call_fileno(inst) == tmp) | ||
497 | return DIE_FIND_CB_CONTINUE; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | iwp->retval = iwp->callback(inst, iwp->data); | ||
502 | |||
503 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * die_walk_instances - Walk on instances of given DIE | ||
508 | * @or_die: an abstract original DIE | ||
509 | * @callback: a callback function which is called with instance DIE | ||
510 | * @data: user data | ||
511 | * | ||
512 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
513 | * declartion. This returns the return value of @callback if it returns | ||
514 | * non-zero value, or -ENOENT if there is no instance. | ||
515 | */ | ||
516 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
517 | void *data) | ||
518 | { | ||
519 | Dwarf_Die cu_die; | ||
520 | Dwarf_Die die_mem; | ||
521 | struct __instance_walk_param iwp = { | ||
522 | .addr = or_die->addr, | ||
523 | .callback = callback, | ||
524 | .data = data, | ||
525 | .retval = -ENOENT, | ||
526 | }; | ||
527 | |||
528 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
529 | return -ENOENT; | ||
530 | |||
531 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
532 | |||
533 | return iwp.retval; | ||
534 | } | ||
535 | |||
377 | /* Line walker internal parameters */ | 536 | /* Line walker internal parameters */ |
378 | struct __line_walk_param { | 537 | struct __line_walk_param { |
379 | const char *fname; | 538 | bool recursive; |
380 | line_walk_callback_t callback; | 539 | line_walk_callback_t callback; |
381 | void *data; | 540 | void *data; |
382 | int retval; | 541 | int retval; |
@@ -385,39 +544,56 @@ struct __line_walk_param { | |||
385 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 544 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
386 | { | 545 | { |
387 | struct __line_walk_param *lw = data; | 546 | struct __line_walk_param *lw = data; |
388 | Dwarf_Addr addr; | 547 | Dwarf_Addr addr = 0; |
548 | const char *fname; | ||
389 | int lineno; | 549 | int lineno; |
390 | 550 | ||
391 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 551 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
552 | fname = die_get_call_file(in_die); | ||
392 | lineno = die_get_call_lineno(in_die); | 553 | lineno = die_get_call_lineno(in_die); |
393 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 554 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
394 | lw->retval = lw->callback(lw->fname, lineno, addr, | 555 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
395 | lw->data); | ||
396 | if (lw->retval != 0) | 556 | if (lw->retval != 0) |
397 | return DIE_FIND_CB_END; | 557 | return DIE_FIND_CB_END; |
398 | } | 558 | } |
399 | } | 559 | } |
400 | return DIE_FIND_CB_SIBLING; | 560 | if (!lw->recursive) |
561 | /* Don't need to search recursively */ | ||
562 | return DIE_FIND_CB_SIBLING; | ||
563 | |||
564 | if (addr) { | ||
565 | fname = dwarf_decl_file(in_die); | ||
566 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | ||
567 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | ||
568 | if (lw->retval != 0) | ||
569 | return DIE_FIND_CB_END; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* Continue to search nested inlined function call-sites */ | ||
574 | return DIE_FIND_CB_CONTINUE; | ||
401 | } | 575 | } |
402 | 576 | ||
403 | /* Walk on lines of blocks included in given DIE */ | 577 | /* Walk on lines of blocks included in given DIE */ |
404 | static int __die_walk_funclines(Dwarf_Die *sp_die, | 578 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
405 | line_walk_callback_t callback, void *data) | 579 | line_walk_callback_t callback, void *data) |
406 | { | 580 | { |
407 | struct __line_walk_param lw = { | 581 | struct __line_walk_param lw = { |
582 | .recursive = recursive, | ||
408 | .callback = callback, | 583 | .callback = callback, |
409 | .data = data, | 584 | .data = data, |
410 | .retval = 0, | 585 | .retval = 0, |
411 | }; | 586 | }; |
412 | Dwarf_Die die_mem; | 587 | Dwarf_Die die_mem; |
413 | Dwarf_Addr addr; | 588 | Dwarf_Addr addr; |
589 | const char *fname; | ||
414 | int lineno; | 590 | int lineno; |
415 | 591 | ||
416 | /* Handle function declaration line */ | 592 | /* Handle function declaration line */ |
417 | lw.fname = dwarf_decl_file(sp_die); | 593 | fname = dwarf_decl_file(sp_die); |
418 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 594 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
419 | dwarf_entrypc(sp_die, &addr) == 0) { | 595 | dwarf_entrypc(sp_die, &addr) == 0) { |
420 | lw.retval = callback(lw.fname, lineno, addr, data); | 596 | lw.retval = callback(fname, lineno, addr, data); |
421 | if (lw.retval != 0) | 597 | if (lw.retval != 0) |
422 | goto done; | 598 | goto done; |
423 | } | 599 | } |
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
430 | { | 606 | { |
431 | struct __line_walk_param *lw = data; | 607 | struct __line_walk_param *lw = data; |
432 | 608 | ||
433 | lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); | 609 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
434 | if (lw->retval != 0) | 610 | if (lw->retval != 0) |
435 | return DWARF_CB_ABORT; | 611 | return DWARF_CB_ABORT; |
436 | 612 | ||
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
439 | 615 | ||
440 | /** | 616 | /** |
441 | * die_walk_lines - Walk on lines inside given DIE | 617 | * die_walk_lines - Walk on lines inside given DIE |
442 | * @rt_die: a root DIE (CU or subprogram) | 618 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) |
443 | * @callback: callback routine | 619 | * @callback: callback routine |
444 | * @data: user data | 620 | * @data: user data |
445 | * | 621 | * |
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
460 | size_t nlines, i; | 636 | size_t nlines, i; |
461 | 637 | ||
462 | /* Get the CU die */ | 638 | /* Get the CU die */ |
463 | if (dwarf_tag(rt_die) == DW_TAG_subprogram) | 639 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) |
464 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); | 640 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); |
465 | else | 641 | else |
466 | cu_die = rt_die; | 642 | cu_die = rt_die; |
467 | if (!cu_die) { | 643 | if (!cu_die) { |
468 | pr_debug2("Failed to get CU from subprogram\n"); | 644 | pr_debug2("Failed to get CU from given DIE.\n"); |
469 | return -EINVAL; | 645 | return -EINVAL; |
470 | } | 646 | } |
471 | 647 | ||
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
509 | * subroutines. We have to check functions list or given function. | 685 | * subroutines. We have to check functions list or given function. |
510 | */ | 686 | */ |
511 | if (rt_die != cu_die) | 687 | if (rt_die != cu_die) |
512 | ret = __die_walk_funclines(rt_die, callback, data); | 688 | /* |
689 | * Don't need walk functions recursively, because nested | ||
690 | * inlined functions don't have lines of the specified DIE. | ||
691 | */ | ||
692 | ret = __die_walk_funclines(rt_die, false, callback, data); | ||
513 | else { | 693 | else { |
514 | struct __line_walk_param param = { | 694 | struct __line_walk_param param = { |
515 | .callback = callback, | 695 | .callback = callback, |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bc3b21167e70..6ce1717784b7 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); | |||
34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
35 | const char **fname, int *lineno); | 35 | const char **fname, int *lineno); |
36 | 36 | ||
37 | /* Walk on funcitons at given address */ | ||
38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
39 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
40 | |||
37 | /* Compare diename and tname */ | 41 | /* Compare diename and tname */ |
38 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
39 | 43 | ||
40 | /* Get callsite line number of inline-function instance */ | 44 | /* Get callsite line number of inline-function instance */ |
41 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 45 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
42 | 46 | ||
47 | /* Get callsite file name of inlined function instance */ | ||
48 | extern const char *die_get_call_file(Dwarf_Die *in_die); | ||
49 | |||
43 | /* Get type die */ | 50 | /* Get type die */ |
44 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
45 | 52 | ||
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
73 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
74 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
75 | 82 | ||
83 | /* Walk on the instances of given DIE */ | ||
84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
86 | |||
76 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
77 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
78 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3c1b8a632101..437f8ca679a0 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, | |||
169 | continue; | 169 | continue; |
170 | pbf += n + 3; | 170 | pbf += n + 3; |
171 | if (*pbf == 'x') { /* vm_exec */ | 171 | if (*pbf == 'x') { /* vm_exec */ |
172 | char anonstr[] = "//anon\n"; | ||
172 | char *execname = strchr(bf, '/'); | 173 | char *execname = strchr(bf, '/'); |
173 | 174 | ||
174 | /* Catch VDSO */ | 175 | /* Catch VDSO */ |
175 | if (execname == NULL) | 176 | if (execname == NULL) |
176 | execname = strstr(bf, "[vdso]"); | 177 | execname = strstr(bf, "[vdso]"); |
177 | 178 | ||
179 | /* Catch anonymous mmaps */ | ||
180 | if ((execname == NULL) && !strstr(bf, "[")) | ||
181 | execname = anonstr; | ||
182 | |||
178 | if (execname == NULL) | 183 | if (execname == NULL) |
179 | continue; | 184 | continue; |
180 | 185 | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1d7f66488a88..357a85b85248 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id); | |||
186 | 186 | ||
187 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 187 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
188 | int sample_size, bool sample_id_all, | 188 | int sample_size, bool sample_id_all, |
189 | struct perf_sample *sample); | 189 | struct perf_sample *sample, bool swapped); |
190 | 190 | ||
191 | #endif /* __PERF_RECORD_H */ | 191 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b021ea9265c3..72e9f4886b6d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -85,10 +85,45 @@ int perf_evlist__add_default(struct perf_evlist *evlist) | |||
85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); | 85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); |
86 | 86 | ||
87 | if (evsel == NULL) | 87 | if (evsel == NULL) |
88 | return -ENOMEM; | 88 | goto error; |
89 | |||
90 | /* use strdup() because free(evsel) assumes name is allocated */ | ||
91 | evsel->name = strdup("cycles"); | ||
92 | if (!evsel->name) | ||
93 | goto error_free; | ||
89 | 94 | ||
90 | perf_evlist__add(evlist, evsel); | 95 | perf_evlist__add(evlist, evsel); |
91 | return 0; | 96 | return 0; |
97 | error_free: | ||
98 | perf_evsel__delete(evsel); | ||
99 | error: | ||
100 | return -ENOMEM; | ||
101 | } | ||
102 | |||
103 | void perf_evlist__disable(struct perf_evlist *evlist) | ||
104 | { | ||
105 | int cpu, thread; | ||
106 | struct perf_evsel *pos; | ||
107 | |||
108 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
109 | list_for_each_entry(pos, &evlist->entries, node) { | ||
110 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
111 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void perf_evlist__enable(struct perf_evlist *evlist) | ||
117 | { | ||
118 | int cpu, thread; | ||
119 | struct perf_evsel *pos; | ||
120 | |||
121 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
122 | list_for_each_entry(pos, &evlist->entries, node) { | ||
123 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
124 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); | ||
125 | } | ||
126 | } | ||
92 | } | 127 | } |
93 | 128 | ||
94 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 129 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index b2b862374f37..f34915002745 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -53,6 +53,9 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist); | |||
53 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | 53 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); |
54 | void perf_evlist__munmap(struct perf_evlist *evlist); | 54 | void perf_evlist__munmap(struct perf_evlist *evlist); |
55 | 55 | ||
56 | void perf_evlist__disable(struct perf_evlist *evlist); | ||
57 | void perf_evlist__enable(struct perf_evlist *evlist); | ||
58 | |||
56 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | 59 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, |
57 | struct cpu_map *cpus, | 60 | struct cpu_map *cpus, |
58 | struct thread_map *threads) | 61 | struct thread_map *threads) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a03a36b7908a..e389815078d3 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <byteswap.h> | ||
11 | #include "asm/bug.h" | ||
10 | #include "evsel.h" | 12 | #include "evsel.h" |
11 | #include "evlist.h" | 13 | #include "evlist.h" |
12 | #include "util.h" | 14 | #include "util.h" |
@@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event, | |||
342 | 344 | ||
343 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 345 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
344 | int sample_size, bool sample_id_all, | 346 | int sample_size, bool sample_id_all, |
345 | struct perf_sample *data) | 347 | struct perf_sample *data, bool swapped) |
346 | { | 348 | { |
347 | const u64 *array; | 349 | const u64 *array; |
348 | 350 | ||
351 | /* | ||
352 | * used for cross-endian analysis. See git commit 65014ab3 | ||
353 | * for why this goofiness is needed. | ||
354 | */ | ||
355 | union { | ||
356 | u64 val64; | ||
357 | u32 val32[2]; | ||
358 | } u; | ||
359 | |||
360 | |||
349 | data->cpu = data->pid = data->tid = -1; | 361 | data->cpu = data->pid = data->tid = -1; |
350 | data->stream_id = data->id = data->time = -1ULL; | 362 | data->stream_id = data->id = data->time = -1ULL; |
351 | 363 | ||
@@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
366 | } | 378 | } |
367 | 379 | ||
368 | if (type & PERF_SAMPLE_TID) { | 380 | if (type & PERF_SAMPLE_TID) { |
369 | u32 *p = (u32 *)array; | 381 | u.val64 = *array; |
370 | data->pid = p[0]; | 382 | if (swapped) { |
371 | data->tid = p[1]; | 383 | /* undo swap of u64, then swap on individual u32s */ |
384 | u.val64 = bswap_64(u.val64); | ||
385 | u.val32[0] = bswap_32(u.val32[0]); | ||
386 | u.val32[1] = bswap_32(u.val32[1]); | ||
387 | } | ||
388 | |||
389 | data->pid = u.val32[0]; | ||
390 | data->tid = u.val32[1]; | ||
372 | array++; | 391 | array++; |
373 | } | 392 | } |
374 | 393 | ||
@@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
395 | } | 414 | } |
396 | 415 | ||
397 | if (type & PERF_SAMPLE_CPU) { | 416 | if (type & PERF_SAMPLE_CPU) { |
398 | u32 *p = (u32 *)array; | 417 | |
399 | data->cpu = *p; | 418 | u.val64 = *array; |
419 | if (swapped) { | ||
420 | /* undo swap of u64, then swap on individual u32s */ | ||
421 | u.val64 = bswap_64(u.val64); | ||
422 | u.val32[0] = bswap_32(u.val32[0]); | ||
423 | } | ||
424 | |||
425 | data->cpu = u.val32[0]; | ||
400 | array++; | 426 | array++; |
401 | } | 427 | } |
402 | 428 | ||
@@ -423,18 +449,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
423 | } | 449 | } |
424 | 450 | ||
425 | if (type & PERF_SAMPLE_RAW) { | 451 | if (type & PERF_SAMPLE_RAW) { |
426 | u32 *p = (u32 *)array; | 452 | const u64 *pdata; |
453 | |||
454 | u.val64 = *array; | ||
455 | if (WARN_ONCE(swapped, | ||
456 | "Endianness of raw data not corrected!\n")) { | ||
457 | /* undo swap of u64, then swap on individual u32s */ | ||
458 | u.val64 = bswap_64(u.val64); | ||
459 | u.val32[0] = bswap_32(u.val32[0]); | ||
460 | u.val32[1] = bswap_32(u.val32[1]); | ||
461 | } | ||
427 | 462 | ||
428 | if (sample_overlap(event, array, sizeof(u32))) | 463 | if (sample_overlap(event, array, sizeof(u32))) |
429 | return -EFAULT; | 464 | return -EFAULT; |
430 | 465 | ||
431 | data->raw_size = *p; | 466 | data->raw_size = u.val32[0]; |
432 | p++; | 467 | pdata = (void *) array + sizeof(u32); |
433 | 468 | ||
434 | if (sample_overlap(event, p, data->raw_size)) | 469 | if (sample_overlap(event, pdata, data->raw_size)) |
435 | return -EFAULT; | 470 | return -EFAULT; |
436 | 471 | ||
437 | data->raw_data = p; | 472 | data->raw_data = (void *) pdata; |
438 | } | 473 | } |
439 | 474 | ||
440 | return 0; | 475 | return 0; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index cb2959a3fb43..b6c1ad123ca9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -189,8 +189,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
189 | const char *name, bool is_kallsyms) | 189 | const char *name, bool is_kallsyms) |
190 | { | 190 | { |
191 | const size_t size = PATH_MAX; | 191 | const size_t size = PATH_MAX; |
192 | char *realname, *filename = malloc(size), | 192 | char *realname, *filename = zalloc(size), |
193 | *linkname = malloc(size), *targetname; | 193 | *linkname = zalloc(size), *targetname; |
194 | int len, err = -1; | 194 | int len, err = -1; |
195 | 195 | ||
196 | if (is_kallsyms) { | 196 | if (is_kallsyms) { |
@@ -254,8 +254,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | |||
254 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | 254 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) |
255 | { | 255 | { |
256 | const size_t size = PATH_MAX; | 256 | const size_t size = PATH_MAX; |
257 | char *filename = malloc(size), | 257 | char *filename = zalloc(size), |
258 | *linkname = malloc(size); | 258 | *linkname = zalloc(size); |
259 | int err = -1; | 259 | int err = -1; |
260 | 260 | ||
261 | if (filename == NULL || linkname == NULL) | 261 | if (filename == NULL || linkname == NULL) |
@@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
726 | return -1; | 726 | return -1; |
727 | 727 | ||
728 | bev.header = old_bev.header; | 728 | bev.header = old_bev.header; |
729 | bev.pid = 0; | 729 | |
730 | /* | ||
731 | * As the pid is the missing value, we need to fill | ||
732 | * it properly. The header.misc value give us nice hint. | ||
733 | */ | ||
734 | bev.pid = HOST_KERNEL_ID; | ||
735 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
736 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
737 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
738 | |||
730 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | 739 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); |
731 | __event_process_build_id(&bev, filename, session); | 740 | __event_process_build_id(&bev, filename, session); |
732 | 741 | ||
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h index 791f9dd27ebf..547628e97f3d 100644 --- a/tools/perf/util/include/linux/compiler.h +++ b/tools/perf/util/include/linux/compiler.h | |||
@@ -5,7 +5,9 @@ | |||
5 | #define __always_inline inline | 5 | #define __always_inline inline |
6 | #endif | 6 | #endif |
7 | #define __user | 7 | #define __user |
8 | #ifndef __attribute_const__ | ||
8 | #define __attribute_const__ | 9 | #define __attribute_const__ |
10 | #endif | ||
9 | 11 | ||
10 | #define __used __attribute__((__unused__)) | 12 | #define __used __attribute__((__unused__)) |
11 | 13 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4ea7e19f5251..928918b796b2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr) | |||
697 | return EVT_FAILED; | 697 | return EVT_FAILED; |
698 | n = hex2u64(str + 1, &config); | 698 | n = hex2u64(str + 1, &config); |
699 | if (n > 0) { | 699 | if (n > 0) { |
700 | *strp = str + n + 1; | 700 | const char *end = str + n + 1; |
701 | if (*end != '\0' && *end != ',' && *end != ':') | ||
702 | return EVT_FAILED; | ||
703 | |||
704 | *strp = end; | ||
701 | attr->type = PERF_TYPE_RAW; | 705 | attr->type = PERF_TYPE_RAW; |
702 | attr->config = config; | 706 | attr->config = config; |
703 | return EVT_HANDLED; | 707 | return EVT_HANDLED; |
@@ -1097,6 +1101,4 @@ void print_events(const char *event_glob) | |||
1097 | printf("\n"); | 1101 | printf("\n"); |
1098 | 1102 | ||
1099 | print_tracepoint_events(NULL, NULL); | 1103 | print_tracepoint_events(NULL, NULL); |
1100 | |||
1101 | exit(129); | ||
1102 | } | 1104 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b82d54fa2c56..1c7bfa5fe0a8 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1820 | ret = -ENOMEM; | 1820 | ret = -ENOMEM; |
1821 | goto error; | 1821 | goto error; |
1822 | } | 1822 | } |
1823 | tev->point.module = strdup(module); | 1823 | |
1824 | if (tev->point.module == NULL) { | 1824 | if (module) { |
1825 | ret = -ENOMEM; | 1825 | tev->point.module = strdup(module); |
1826 | goto error; | 1826 | if (tev->point.module == NULL) { |
1827 | ret = -ENOMEM; | ||
1828 | goto error; | ||
1829 | } | ||
1827 | } | 1830 | } |
1831 | |||
1828 | tev->point.offset = pev->point.offset; | 1832 | tev->point.offset = pev->point.offset; |
1829 | tev->point.retprobe = pev->point.retprobe; | 1833 | tev->point.retprobe = pev->point.retprobe; |
1830 | tev->nargs = pev->nargs; | 1834 | tev->nargs = pev->nargs; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e44a3e36519..5d732621a462 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
612 | return ret; | 612 | return ret; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* Find a variable in a subprogram die */ | 615 | /* Find a variable in a scope DIE */ |
616 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
617 | { | 617 | { |
618 | Dwarf_Die vr_die, *scopes; | 618 | Dwarf_Die vr_die; |
619 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
620 | int ret, nscopes; | 620 | int ret = 0; |
621 | 621 | ||
622 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
623 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
652 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
653 | return -ENOMEM; | 653 | return -ENOMEM; |
654 | 654 | ||
655 | pr_debug("Searching '%s' variable in context.\n", | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
656 | pf->pvar->var); | ||
657 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
658 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
659 | ret = convert_variable(&vr_die, pf); | 658 | /* Search again in global variables */ |
660 | else { | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
661 | /* Search upper class */ | 660 | ret = -ENOENT; |
662 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | ||
663 | while (nscopes-- > 1) { | ||
664 | pr_debug("Searching variables in %s\n", | ||
665 | dwarf_diename(&scopes[nscopes])); | ||
666 | /* We should check this scope, so give dummy address */ | ||
667 | if (die_find_variable_at(&scopes[nscopes], | ||
668 | pf->pvar->var, 0, | ||
669 | &vr_die)) { | ||
670 | ret = convert_variable(&vr_die, pf); | ||
671 | goto found; | ||
672 | } | ||
673 | } | ||
674 | if (scopes) | ||
675 | free(scopes); | ||
676 | ret = -ENOENT; | ||
677 | } | 661 | } |
678 | found: | 662 | if (ret >= 0) |
663 | ret = convert_variable(&vr_die, pf); | ||
664 | |||
679 | if (ret < 0) | 665 | if (ret < 0) |
680 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
681 | pf->pvar->var); | 667 | pf->pvar->var); |
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | |||
718 | return 0; | 704 | return 0; |
719 | } | 705 | } |
720 | 706 | ||
721 | /* Call probe_finder callback with real subprogram DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
722 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
723 | { | 709 | { |
724 | Dwarf_Die die_mem; | ||
725 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
726 | size_t nops; | 711 | size_t nops; |
727 | int ret; | 712 | int ret; |
728 | 713 | ||
729 | /* If no real subprogram, find a real one */ | 714 | if (!sc_die) { |
730 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
731 | sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); | 716 | return -EINVAL; |
732 | if (!sp_die) { | 717 | } |
718 | |||
719 | /* If not a real subprogram, find a real one */ | ||
720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | ||
721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | ||
733 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
734 | "functions.\n"); | 723 | "functions.\n"); |
735 | return -ENOENT; | 724 | return -ENOENT; |
736 | } | 725 | } |
737 | } | 726 | } else |
727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | ||
738 | 728 | ||
739 | /* Get the frame base attribute/ops */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
740 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
741 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
742 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
743 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
755 | } | 745 | } |
756 | 746 | ||
757 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
758 | ret = pf->callback(sp_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
759 | 749 | ||
760 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
761 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
763 | return ret; | 753 | return ret; |
764 | } | 754 | } |
765 | 755 | ||
756 | struct find_scope_param { | ||
757 | const char *function; | ||
758 | const char *file; | ||
759 | int line; | ||
760 | int diff; | ||
761 | Dwarf_Die *die_mem; | ||
762 | bool found; | ||
763 | }; | ||
764 | |||
765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | ||
766 | { | ||
767 | struct find_scope_param *fsp = data; | ||
768 | const char *file; | ||
769 | int lno; | ||
770 | |||
771 | /* Skip if declared file name does not match */ | ||
772 | if (fsp->file) { | ||
773 | file = dwarf_decl_file(fn_die); | ||
774 | if (!file || strcmp(fsp->file, file) != 0) | ||
775 | return 0; | ||
776 | } | ||
777 | /* If the function name is given, that's what user expects */ | ||
778 | if (fsp->function) { | ||
779 | if (die_compare_name(fn_die, fsp->function)) { | ||
780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
781 | fsp->found = true; | ||
782 | return 1; | ||
783 | } | ||
784 | } else { | ||
785 | /* With the line number, find the nearest declared DIE */ | ||
786 | dwarf_decl_line(fn_die, &lno); | ||
787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | ||
788 | /* Keep a candidate and continue */ | ||
789 | fsp->diff = fsp->line - lno; | ||
790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
791 | fsp->found = true; | ||
792 | } | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | /* Find an appropriate scope fits to given conditions */ | ||
798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | ||
799 | { | ||
800 | struct find_scope_param fsp = { | ||
801 | .function = pf->pev->point.function, | ||
802 | .file = pf->fname, | ||
803 | .line = pf->lno, | ||
804 | .diff = INT_MAX, | ||
805 | .die_mem = die_mem, | ||
806 | .found = false, | ||
807 | }; | ||
808 | |||
809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | ||
810 | |||
811 | return fsp.found ? die_mem : NULL; | ||
812 | } | ||
813 | |||
766 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
767 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
768 | { | 816 | { |
769 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
818 | Dwarf_Die *sc_die, die_mem; | ||
770 | int ret; | 819 | int ret; |
771 | 820 | ||
772 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
773 | return 0; | 822 | return 0; |
774 | 823 | ||
775 | pf->addr = addr; | 824 | pf->addr = addr; |
776 | ret = call_probe_finder(NULL, pf); | 825 | sc_die = find_best_scope(pf, &die_mem); |
826 | if (!sc_die) { | ||
827 | pr_warning("Failed to find scope of probe point.\n"); | ||
828 | return -ENOENT; | ||
829 | } | ||
830 | |||
831 | ret = call_probe_finder(sc_die, pf); | ||
777 | 832 | ||
778 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
779 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
827 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
828 | { | 883 | { |
829 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
885 | Dwarf_Die *sc_die, die_mem; | ||
830 | int ret; | 886 | int ret; |
831 | 887 | ||
832 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
836 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
837 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
838 | pf->addr = addr; | 894 | pf->addr = addr; |
839 | ret = call_probe_finder(NULL, pf); | 895 | pf->lno = lineno; |
896 | sc_die = find_best_scope(pf, &die_mem); | ||
897 | if (!sc_die) { | ||
898 | pr_warning("Failed to find scope of probe point.\n"); | ||
899 | return -ENOENT; | ||
900 | } | ||
901 | |||
902 | ret = call_probe_finder(sc_die, pf); | ||
840 | 903 | ||
841 | /* | 904 | /* |
842 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
861 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
862 | } | 925 | } |
863 | 926 | ||
864 | /* Callback parameter with return value */ | ||
865 | struct dwarf_callback_param { | ||
866 | void *data; | ||
867 | int retval; | ||
868 | }; | ||
869 | |||
870 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
871 | { | 928 | { |
872 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
873 | struct probe_finder *pf = param->data; | ||
874 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
875 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
932 | int ret; | ||
876 | 933 | ||
877 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
878 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
879 | else { | 936 | else { |
880 | /* Get probe address */ | 937 | /* Get probe address */ |
881 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
882 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
883 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
884 | param->retval = -ENOENT; | 941 | return -ENOENT; |
885 | return DWARF_CB_ABORT; | ||
886 | } | 942 | } |
887 | pf->addr = addr; | 943 | pf->addr = addr; |
888 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
889 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
890 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
891 | 947 | ||
892 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
893 | if (param->retval < 0) | ||
894 | return DWARF_CB_ABORT; | ||
895 | } | 949 | } |
896 | 950 | ||
897 | return DWARF_CB_OK; | 951 | return ret; |
898 | } | 952 | } |
899 | 953 | ||
954 | /* Callback parameter with return value for libdw */ | ||
955 | struct dwarf_callback_param { | ||
956 | void *data; | ||
957 | int retval; | ||
958 | }; | ||
959 | |||
900 | /* Search function from function name */ | 960 | /* Search function from function name */ |
901 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
902 | { | 962 | { |
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
933 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
934 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
935 | } | 995 | } |
936 | } else { | 996 | } else |
937 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
938 | .retval = 0}; | ||
939 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
940 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
941 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
942 | param->retval = _param.retval; | ||
943 | } | ||
944 | 1000 | ||
945 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
946 | } | 1002 | } |
@@ -1060,7 +1116,7 @@ found: | |||
1060 | } | 1116 | } |
1061 | 1117 | ||
1062 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
1063 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1064 | { | 1120 | { |
1065 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
1066 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1075 | } | 1131 | } |
1076 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
1077 | 1133 | ||
1078 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1134 | /* Trace point should be converted from subprogram DIE */ |
1079 | &tev->point); | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1136 | pf->pev->point.retprobe, &tev->point); | ||
1080 | if (ret < 0) | 1137 | if (ret < 0) |
1081 | return ret; | 1138 | return ret; |
1082 | 1139 | ||
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1091 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
1092 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
1093 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
1094 | ret = find_variable(sp_die, pf); | 1151 | /* Variable should be found from scope DIE */ |
1152 | ret = find_variable(sc_die, pf); | ||
1095 | if (ret != 0) | 1153 | if (ret != 0) |
1096 | return ret; | 1154 | return ret; |
1097 | } | 1155 | } |
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1159 | } | 1217 | } |
1160 | 1218 | ||
1161 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
1162 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
1163 | { | 1221 | { |
1164 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
1165 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
1166 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
1167 | Dwarf_Die die_mem, *scopes = NULL; | 1225 | Dwarf_Die die_mem; |
1168 | int ret, nscopes; | 1226 | int ret; |
1169 | 1227 | ||
1170 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
1171 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1174 | } | 1232 | } |
1175 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
1176 | 1234 | ||
1177 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1235 | /* Trace point should be converted from subprogram DIE */ |
1178 | &vl->point); | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1237 | pf->pev->point.retprobe, &vl->point); | ||
1179 | if (ret < 0) | 1238 | if (ret < 0) |
1180 | return ret; | 1239 | return ret; |
1181 | 1240 | ||
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1187 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
1188 | return -ENOMEM; | 1247 | return -ENOMEM; |
1189 | af->child = true; | 1248 | af->child = true; |
1190 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
1191 | 1250 | ||
1192 | /* Find external variables */ | 1251 | /* Find external variables */ |
1193 | if (!af->externs) | 1252 | if (!af->externs) |
1194 | goto out; | 1253 | goto out; |
1195 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
1196 | af->child = false; | 1255 | af->child = false; |
1197 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
1198 | while (nscopes-- > 1) | ||
1199 | die_find_child(&scopes[nscopes], collect_variables_cb, | ||
1200 | (void *)af, &die_mem); | ||
1201 | if (scopes) | ||
1202 | free(scopes); | ||
1203 | 1257 | ||
1204 | out: | 1258 | out: |
1205 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1391 | 1445 | ||
1392 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1393 | { | 1447 | { |
1394 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
1395 | 1449 | ||
1396 | param->retval = find_line_range_by_line(in_die, param->data); | 1450 | /* |
1397 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1451 | * We have to check all instances of inlined function, because |
1452 | * some execution paths can be optimized out depends on the | ||
1453 | * function argument of instances | ||
1454 | */ | ||
1455 | return 0; | ||
1398 | } | 1456 | } |
1399 | 1457 | ||
1400 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1422 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1423 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
1424 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
1425 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
1426 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
1427 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
1428 | _param.retval = 0; | 1486 | else |
1429 | dwarf_func_inline_instances(sp_die, | ||
1430 | line_range_inline_cb, | ||
1431 | &_param); | ||
1432 | param->retval = _param.retval; | ||
1433 | } else | ||
1434 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1435 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
1436 | } | 1489 | } |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index c478b42a2473..1132c8f0ce89 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -57,7 +57,7 @@ struct probe_finder { | |||
57 | struct perf_probe_event *pev; /* Target probe event */ | 57 | struct perf_probe_event *pev; /* Target probe event */ |
58 | 58 | ||
59 | /* Callback when a probe point is found */ | 59 | /* Callback when a probe point is found */ |
60 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); | 60 | int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf); |
61 | 61 | ||
62 | /* For function searching */ | 62 | /* For function searching */ |
63 | int lno; /* Line number */ | 63 | int lno; /* Line number */ |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 8e0b5a39d8a7..7624324efad4 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -187,16 +187,119 @@ static PyTypeObject pyrf_throttle_event__type = { | |||
187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, | 187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, |
188 | }; | 188 | }; |
189 | 189 | ||
190 | static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); | ||
191 | |||
192 | static PyMemberDef pyrf_lost_event__members[] = { | ||
193 | sample_members | ||
194 | member_def(lost_event, id, T_ULONGLONG, "event id"), | ||
195 | member_def(lost_event, lost, T_ULONGLONG, "number of lost events"), | ||
196 | { .name = NULL, }, | ||
197 | }; | ||
198 | |||
199 | static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) | ||
200 | { | ||
201 | PyObject *ret; | ||
202 | char *s; | ||
203 | |||
204 | if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", " | ||
205 | "lost: %#" PRIx64 " }", | ||
206 | pevent->event.lost.id, pevent->event.lost.lost) < 0) { | ||
207 | ret = PyErr_NoMemory(); | ||
208 | } else { | ||
209 | ret = PyString_FromString(s); | ||
210 | free(s); | ||
211 | } | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | static PyTypeObject pyrf_lost_event__type = { | ||
216 | PyVarObject_HEAD_INIT(NULL, 0) | ||
217 | .tp_name = "perf.lost_event", | ||
218 | .tp_basicsize = sizeof(struct pyrf_event), | ||
219 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
220 | .tp_doc = pyrf_lost_event__doc, | ||
221 | .tp_members = pyrf_lost_event__members, | ||
222 | .tp_repr = (reprfunc)pyrf_lost_event__repr, | ||
223 | }; | ||
224 | |||
225 | static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); | ||
226 | |||
227 | static PyMemberDef pyrf_read_event__members[] = { | ||
228 | sample_members | ||
229 | member_def(read_event, pid, T_UINT, "event pid"), | ||
230 | member_def(read_event, tid, T_UINT, "event tid"), | ||
231 | { .name = NULL, }, | ||
232 | }; | ||
233 | |||
234 | static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent) | ||
235 | { | ||
236 | return PyString_FromFormat("{ type: read, pid: %u, tid: %u }", | ||
237 | pevent->event.read.pid, | ||
238 | pevent->event.read.tid); | ||
239 | /* | ||
240 | * FIXME: return the array of read values, | ||
241 | * making this method useful ;-) | ||
242 | */ | ||
243 | } | ||
244 | |||
245 | static PyTypeObject pyrf_read_event__type = { | ||
246 | PyVarObject_HEAD_INIT(NULL, 0) | ||
247 | .tp_name = "perf.read_event", | ||
248 | .tp_basicsize = sizeof(struct pyrf_event), | ||
249 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
250 | .tp_doc = pyrf_read_event__doc, | ||
251 | .tp_members = pyrf_read_event__members, | ||
252 | .tp_repr = (reprfunc)pyrf_read_event__repr, | ||
253 | }; | ||
254 | |||
255 | static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object."); | ||
256 | |||
257 | static PyMemberDef pyrf_sample_event__members[] = { | ||
258 | sample_members | ||
259 | member_def(perf_event_header, type, T_UINT, "event type"), | ||
260 | { .name = NULL, }, | ||
261 | }; | ||
262 | |||
263 | static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) | ||
264 | { | ||
265 | PyObject *ret; | ||
266 | char *s; | ||
267 | |||
268 | if (asprintf(&s, "{ type: sample }") < 0) { | ||
269 | ret = PyErr_NoMemory(); | ||
270 | } else { | ||
271 | ret = PyString_FromString(s); | ||
272 | free(s); | ||
273 | } | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static PyTypeObject pyrf_sample_event__type = { | ||
278 | PyVarObject_HEAD_INIT(NULL, 0) | ||
279 | .tp_name = "perf.sample_event", | ||
280 | .tp_basicsize = sizeof(struct pyrf_event), | ||
281 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
282 | .tp_doc = pyrf_sample_event__doc, | ||
283 | .tp_members = pyrf_sample_event__members, | ||
284 | .tp_repr = (reprfunc)pyrf_sample_event__repr, | ||
285 | }; | ||
286 | |||
190 | static int pyrf_event__setup_types(void) | 287 | static int pyrf_event__setup_types(void) |
191 | { | 288 | { |
192 | int err; | 289 | int err; |
193 | pyrf_mmap_event__type.tp_new = | 290 | pyrf_mmap_event__type.tp_new = |
194 | pyrf_task_event__type.tp_new = | 291 | pyrf_task_event__type.tp_new = |
195 | pyrf_comm_event__type.tp_new = | 292 | pyrf_comm_event__type.tp_new = |
293 | pyrf_lost_event__type.tp_new = | ||
294 | pyrf_read_event__type.tp_new = | ||
295 | pyrf_sample_event__type.tp_new = | ||
196 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; | 296 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; |
197 | err = PyType_Ready(&pyrf_mmap_event__type); | 297 | err = PyType_Ready(&pyrf_mmap_event__type); |
198 | if (err < 0) | 298 | if (err < 0) |
199 | goto out; | 299 | goto out; |
300 | err = PyType_Ready(&pyrf_lost_event__type); | ||
301 | if (err < 0) | ||
302 | goto out; | ||
200 | err = PyType_Ready(&pyrf_task_event__type); | 303 | err = PyType_Ready(&pyrf_task_event__type); |
201 | if (err < 0) | 304 | if (err < 0) |
202 | goto out; | 305 | goto out; |
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void) | |||
206 | err = PyType_Ready(&pyrf_throttle_event__type); | 309 | err = PyType_Ready(&pyrf_throttle_event__type); |
207 | if (err < 0) | 310 | if (err < 0) |
208 | goto out; | 311 | goto out; |
312 | err = PyType_Ready(&pyrf_read_event__type); | ||
313 | if (err < 0) | ||
314 | goto out; | ||
315 | err = PyType_Ready(&pyrf_sample_event__type); | ||
316 | if (err < 0) | ||
317 | goto out; | ||
209 | out: | 318 | out: |
210 | return err; | 319 | return err; |
211 | } | 320 | } |
212 | 321 | ||
213 | static PyTypeObject *pyrf_event__type[] = { | 322 | static PyTypeObject *pyrf_event__type[] = { |
214 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, | 323 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, |
215 | [PERF_RECORD_LOST] = &pyrf_mmap_event__type, | 324 | [PERF_RECORD_LOST] = &pyrf_lost_event__type, |
216 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, | 325 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, |
217 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, | 326 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, |
218 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, | 327 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, |
219 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, | 328 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, |
220 | [PERF_RECORD_FORK] = &pyrf_task_event__type, | 329 | [PERF_RECORD_FORK] = &pyrf_task_event__type, |
221 | [PERF_RECORD_READ] = &pyrf_mmap_event__type, | 330 | [PERF_RECORD_READ] = &pyrf_read_event__type, |
222 | [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, | 331 | [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type, |
223 | }; | 332 | }; |
224 | 333 | ||
225 | static PyObject *pyrf_event__new(union perf_event *event) | 334 | static PyObject *pyrf_event__new(union perf_event *event) |
@@ -694,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
694 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 803 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
695 | err = perf_event__parse_sample(event, first->attr.sample_type, | 804 | err = perf_event__parse_sample(event, first->attr.sample_type, |
696 | perf_evsel__sample_size(first), | 805 | perf_evsel__sample_size(first), |
697 | sample_id_all, &pevent->sample); | 806 | sample_id_all, &pevent->sample, false); |
698 | if (err) | 807 | if (err) |
699 | return PyErr_Format(PyExc_OSError, | 808 | return PyErr_Format(PyExc_OSError, |
700 | "perf: can't parse sample, err=%d", err); | 809 | "perf: can't parse sample, err=%d", err); |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 170601e67d6b..974d0cbee5e9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session, | |||
162 | { | 162 | { |
163 | return perf_event__parse_sample(event, session->sample_type, | 163 | return perf_event__parse_sample(event, session->sample_type, |
164 | session->sample_size, | 164 | session->sample_size, |
165 | session->sample_id_all, sample); | 165 | session->sample_id_all, sample, |
166 | session->header.needs_swap); | ||
166 | } | 167 | } |
167 | 168 | ||
168 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 169 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index bbc982f5dd8b..95d370074928 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -3,9 +3,27 @@ | |||
3 | from distutils.core import setup, Extension | 3 | from distutils.core import setup, Extension |
4 | from os import getenv | 4 | from os import getenv |
5 | 5 | ||
6 | from distutils.command.build_ext import build_ext as _build_ext | ||
7 | from distutils.command.install_lib import install_lib as _install_lib | ||
8 | |||
9 | class build_ext(_build_ext): | ||
10 | def finalize_options(self): | ||
11 | _build_ext.finalize_options(self) | ||
12 | self.build_lib = build_lib | ||
13 | self.build_temp = build_tmp | ||
14 | |||
15 | class install_lib(_install_lib): | ||
16 | def finalize_options(self): | ||
17 | _install_lib.finalize_options(self) | ||
18 | self.build_dir = build_lib | ||
19 | |||
20 | |||
6 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] | 21 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] |
7 | cflags += getenv('CFLAGS', '').split() | 22 | cflags += getenv('CFLAGS', '').split() |
8 | 23 | ||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | ||
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | ||
26 | |||
9 | perf = Extension('perf', | 27 | perf = Extension('perf', |
10 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', | 28 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', |
11 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', | 29 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', |
@@ -21,4 +39,5 @@ setup(name='perf', | |||
21 | author_email='acme@redhat.com', | 39 | author_email='acme@redhat.com', |
22 | license='GPLv2', | 40 | license='GPLv2', |
23 | url='http://perf.wiki.kernel.org', | 41 | url='http://perf.wiki.kernel.org', |
24 | ext_modules=[perf]) | 42 | ext_modules=[perf], |
43 | cmdclass={'build_ext': build_ext, 'install_lib': install_lib}) | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 401e220566fd..1ee8f1e40f18 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
151 | { | 151 | { |
152 | u64 ip_l, ip_r; | 152 | u64 ip_l, ip_r; |
153 | 153 | ||
154 | if (!left->ms.sym && !right->ms.sym) | ||
155 | return right->level - left->level; | ||
156 | |||
157 | if (!left->ms.sym || !right->ms.sym) | ||
158 | return cmp_null(left->ms.sym, right->ms.sym); | ||
159 | |||
154 | if (left->ms.sym == right->ms.sym) | 160 | if (left->ms.sym == right->ms.sym) |
155 | return 0; | 161 | return 0; |
156 | 162 | ||
157 | ip_l = left->ms.sym ? left->ms.sym->start : left->ip; | 163 | ip_l = left->ms.sym->start; |
158 | ip_r = right->ms.sym ? right->ms.sym->start : right->ip; | 164 | ip_r = right->ms.sym->start; |
159 | 165 | ||
160 | return (int64_t)(ip_r - ip_l); | 166 | return (int64_t)(ip_r - ip_l); |
161 | } | 167 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index eec196329fd9..40eeaf07725b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -74,16 +74,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | |||
74 | 74 | ||
75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
76 | { | 76 | { |
77 | symbol_type = toupper(symbol_type); | ||
78 | |||
77 | switch (map_type) { | 79 | switch (map_type) { |
78 | case MAP__FUNCTION: | 80 | case MAP__FUNCTION: |
79 | return symbol_type == 'T' || symbol_type == 'W'; | 81 | return symbol_type == 'T' || symbol_type == 'W'; |
80 | case MAP__VARIABLE: | 82 | case MAP__VARIABLE: |
81 | return symbol_type == 'D' || symbol_type == 'd'; | 83 | return symbol_type == 'D'; |
82 | default: | 84 | default: |
83 | return false; | 85 | return false; |
84 | } | 86 | } |
85 | } | 87 | } |
86 | 88 | ||
89 | static int prefix_underscores_count(const char *str) | ||
90 | { | ||
91 | const char *tail = str; | ||
92 | |||
93 | while (*tail == '_') | ||
94 | tail++; | ||
95 | |||
96 | return tail - str; | ||
97 | } | ||
98 | |||
99 | #define SYMBOL_A 0 | ||
100 | #define SYMBOL_B 1 | ||
101 | |||
102 | static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | ||
103 | { | ||
104 | s64 a; | ||
105 | s64 b; | ||
106 | |||
107 | /* Prefer a symbol with non zero length */ | ||
108 | a = syma->end - syma->start; | ||
109 | b = symb->end - symb->start; | ||
110 | if ((b == 0) && (a > 0)) | ||
111 | return SYMBOL_A; | ||
112 | else if ((a == 0) && (b > 0)) | ||
113 | return SYMBOL_B; | ||
114 | |||
115 | /* Prefer a non weak symbol over a weak one */ | ||
116 | a = syma->binding == STB_WEAK; | ||
117 | b = symb->binding == STB_WEAK; | ||
118 | if (b && !a) | ||
119 | return SYMBOL_A; | ||
120 | if (a && !b) | ||
121 | return SYMBOL_B; | ||
122 | |||
123 | /* Prefer a global symbol over a non global one */ | ||
124 | a = syma->binding == STB_GLOBAL; | ||
125 | b = symb->binding == STB_GLOBAL; | ||
126 | if (a && !b) | ||
127 | return SYMBOL_A; | ||
128 | if (b && !a) | ||
129 | return SYMBOL_B; | ||
130 | |||
131 | /* Prefer a symbol with less underscores */ | ||
132 | a = prefix_underscores_count(syma->name); | ||
133 | b = prefix_underscores_count(symb->name); | ||
134 | if (b > a) | ||
135 | return SYMBOL_A; | ||
136 | else if (a > b) | ||
137 | return SYMBOL_B; | ||
138 | |||
139 | /* If all else fails, choose the symbol with the longest name */ | ||
140 | if (strlen(syma->name) >= strlen(symb->name)) | ||
141 | return SYMBOL_A; | ||
142 | else | ||
143 | return SYMBOL_B; | ||
144 | } | ||
145 | |||
146 | static void symbols__fixup_duplicate(struct rb_root *symbols) | ||
147 | { | ||
148 | struct rb_node *nd; | ||
149 | struct symbol *curr, *next; | ||
150 | |||
151 | nd = rb_first(symbols); | ||
152 | |||
153 | while (nd) { | ||
154 | curr = rb_entry(nd, struct symbol, rb_node); | ||
155 | again: | ||
156 | nd = rb_next(&curr->rb_node); | ||
157 | next = rb_entry(nd, struct symbol, rb_node); | ||
158 | |||
159 | if (!nd) | ||
160 | break; | ||
161 | |||
162 | if (curr->start != next->start) | ||
163 | continue; | ||
164 | |||
165 | if (choose_best_symbol(curr, next) == SYMBOL_A) { | ||
166 | rb_erase(&next->rb_node, symbols); | ||
167 | goto again; | ||
168 | } else { | ||
169 | nd = rb_next(&curr->rb_node); | ||
170 | rb_erase(&curr->rb_node, symbols); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
87 | static void symbols__fixup_end(struct rb_root *symbols) | 175 | static void symbols__fixup_end(struct rb_root *symbols) |
88 | { | 176 | { |
89 | struct rb_node *nd, *prevnd = rb_first(symbols); | 177 | struct rb_node *nd, *prevnd = rb_first(symbols); |
@@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg, | |||
438 | char *line = NULL; | 526 | char *line = NULL; |
439 | size_t n; | 527 | size_t n; |
440 | int err = -1; | 528 | int err = -1; |
441 | u64 prev_start = 0; | ||
442 | char prev_symbol_type = 0; | ||
443 | char *prev_symbol_name; | ||
444 | FILE *file = fopen(filename, "r"); | 529 | FILE *file = fopen(filename, "r"); |
445 | 530 | ||
446 | if (file == NULL) | 531 | if (file == NULL) |
447 | goto out_failure; | 532 | goto out_failure; |
448 | 533 | ||
449 | prev_symbol_name = malloc(KSYM_NAME_LEN); | ||
450 | if (prev_symbol_name == NULL) | ||
451 | goto out_close; | ||
452 | |||
453 | err = 0; | 534 | err = 0; |
454 | 535 | ||
455 | while (!feof(file)) { | 536 | while (!feof(file)) { |
@@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg, | |||
470 | if (len + 2 >= line_len) | 551 | if (len + 2 >= line_len) |
471 | continue; | 552 | continue; |
472 | 553 | ||
473 | symbol_type = toupper(line[len]); | 554 | symbol_type = line[len]; |
474 | len += 2; | 555 | len += 2; |
475 | symbol_name = line + len; | 556 | symbol_name = line + len; |
476 | len = line_len - len; | 557 | len = line_len - len; |
@@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg, | |||
480 | break; | 561 | break; |
481 | } | 562 | } |
482 | 563 | ||
483 | if (prev_symbol_type) { | 564 | /* |
484 | u64 end = start; | 565 | * module symbols are not sorted so we add all |
485 | if (end != prev_start) | 566 | * symbols with zero length and rely on |
486 | --end; | 567 | * symbols__fixup_end() to fix it up. |
487 | err = process_symbol(arg, prev_symbol_name, | 568 | */ |
488 | prev_symbol_type, prev_start, end); | 569 | err = process_symbol(arg, symbol_name, |
489 | if (err) | 570 | symbol_type, start, start); |
490 | break; | 571 | if (err) |
491 | } | 572 | break; |
492 | |||
493 | memcpy(prev_symbol_name, symbol_name, len + 1); | ||
494 | prev_symbol_type = symbol_type; | ||
495 | prev_start = start; | ||
496 | } | 573 | } |
497 | 574 | ||
498 | free(prev_symbol_name); | ||
499 | free(line); | 575 | free(line); |
500 | out_close: | ||
501 | fclose(file); | 576 | fclose(file); |
502 | return err; | 577 | return err; |
503 | 578 | ||
@@ -703,6 +778,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
703 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 778 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
704 | return -1; | 779 | return -1; |
705 | 780 | ||
781 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
782 | symbols__fixup_end(&dso->symbols[map->type]); | ||
783 | |||
706 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 784 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
707 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; | 785 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; |
708 | else | 786 | else |
@@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1092 | if (dso->has_build_id) { | 1170 | if (dso->has_build_id) { |
1093 | u8 build_id[BUILD_ID_SIZE]; | 1171 | u8 build_id[BUILD_ID_SIZE]; |
1094 | 1172 | ||
1095 | if (elf_read_build_id(elf, build_id, | 1173 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) |
1096 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | ||
1097 | goto out_elf_end; | 1174 | goto out_elf_end; |
1098 | 1175 | ||
1099 | if (!dso__build_id_equal(dso, build_id)) | 1176 | if (!dso__build_id_equal(dso, build_id)) |
@@ -1111,6 +1188,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1111 | } | 1188 | } |
1112 | 1189 | ||
1113 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | 1190 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); |
1191 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1192 | opdsec = NULL; | ||
1114 | if (opdsec) | 1193 | if (opdsec) |
1115 | opddata = elf_rawdata(opdsec, NULL); | 1194 | opddata = elf_rawdata(opdsec, NULL); |
1116 | 1195 | ||
@@ -1276,6 +1355,7 @@ new_symbol: | |||
1276 | * For misannotated, zeroed, ASM function sizes. | 1355 | * For misannotated, zeroed, ASM function sizes. |
1277 | */ | 1356 | */ |
1278 | if (nr > 0) { | 1357 | if (nr > 0) { |
1358 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1279 | symbols__fixup_end(&dso->symbols[map->type]); | 1359 | symbols__fixup_end(&dso->symbols[map->type]); |
1280 | if (kmap) { | 1360 | if (kmap) { |
1281 | /* | 1361 | /* |
@@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1362 | ptr = data->d_buf; | 1442 | ptr = data->d_buf; |
1363 | while (ptr < (data->d_buf + data->d_size)) { | 1443 | while (ptr < (data->d_buf + data->d_size)) { |
1364 | GElf_Nhdr *nhdr = ptr; | 1444 | GElf_Nhdr *nhdr = ptr; |
1365 | int namesz = NOTE_ALIGN(nhdr->n_namesz), | 1445 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), |
1366 | descsz = NOTE_ALIGN(nhdr->n_descsz); | 1446 | descsz = NOTE_ALIGN(nhdr->n_descsz); |
1367 | const char *name; | 1447 | const char *name; |
1368 | 1448 | ||
1369 | ptr += sizeof(*nhdr); | 1449 | ptr += sizeof(*nhdr); |
@@ -1372,8 +1452,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1372 | if (nhdr->n_type == NT_GNU_BUILD_ID && | 1452 | if (nhdr->n_type == NT_GNU_BUILD_ID && |
1373 | nhdr->n_namesz == sizeof("GNU")) { | 1453 | nhdr->n_namesz == sizeof("GNU")) { |
1374 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | 1454 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { |
1375 | memcpy(bf, ptr, BUILD_ID_SIZE); | 1455 | size_t sz = min(size, descsz); |
1376 | err = BUILD_ID_SIZE; | 1456 | memcpy(bf, ptr, sz); |
1457 | memset(bf + sz, 0, size - sz); | ||
1458 | err = descsz; | ||
1377 | break; | 1459 | break; |
1378 | } | 1460 | } |
1379 | } | 1461 | } |
@@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1425 | while (1) { | 1507 | while (1) { |
1426 | char bf[BUFSIZ]; | 1508 | char bf[BUFSIZ]; |
1427 | GElf_Nhdr nhdr; | 1509 | GElf_Nhdr nhdr; |
1428 | int namesz, descsz; | 1510 | size_t namesz, descsz; |
1429 | 1511 | ||
1430 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | 1512 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) |
1431 | break; | 1513 | break; |
@@ -1434,15 +1516,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1434 | descsz = NOTE_ALIGN(nhdr.n_descsz); | 1516 | descsz = NOTE_ALIGN(nhdr.n_descsz); |
1435 | if (nhdr.n_type == NT_GNU_BUILD_ID && | 1517 | if (nhdr.n_type == NT_GNU_BUILD_ID && |
1436 | nhdr.n_namesz == sizeof("GNU")) { | 1518 | nhdr.n_namesz == sizeof("GNU")) { |
1437 | if (read(fd, bf, namesz) != namesz) | 1519 | if (read(fd, bf, namesz) != (ssize_t)namesz) |
1438 | break; | 1520 | break; |
1439 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | 1521 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { |
1440 | if (read(fd, build_id, | 1522 | size_t sz = min(descsz, size); |
1441 | BUILD_ID_SIZE) == BUILD_ID_SIZE) { | 1523 | if (read(fd, build_id, sz) == (ssize_t)sz) { |
1524 | memset(build_id + sz, 0, size - sz); | ||
1442 | err = 0; | 1525 | err = 0; |
1443 | break; | 1526 | break; |
1444 | } | 1527 | } |
1445 | } else if (read(fd, bf, descsz) != descsz) | 1528 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) |
1446 | break; | 1529 | break; |
1447 | } else { | 1530 | } else { |
1448 | int n = namesz + descsz; | 1531 | int n = namesz + descsz; |
@@ -1504,6 +1587,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1504 | dso->adjust_symbols = 0; | 1587 | dso->adjust_symbols = 0; |
1505 | 1588 | ||
1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 1589 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
1590 | struct stat st; | ||
1591 | |||
1592 | if (lstat(dso->name, &st) < 0) | ||
1593 | return -1; | ||
1594 | |||
1595 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
1596 | pr_warning("File %s not owned by current user or root, " | ||
1597 | "ignoring it.\n", dso->name); | ||
1598 | return -1; | ||
1599 | } | ||
1600 | |||
1507 | ret = dso__load_perf_map(dso, map, filter); | 1601 | ret = dso__load_perf_map(dso, map, filter); |
1508 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : | 1602 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : |
1509 | SYMTAB__NOT_FOUND; | 1603 | SYMTAB__NOT_FOUND; |
@@ -2170,27 +2264,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
2170 | return ret; | 2264 | return ret; |
2171 | } | 2265 | } |
2172 | 2266 | ||
2173 | struct dso *dso__new_kernel(const char *name) | 2267 | static struct dso* |
2268 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
2269 | const char *short_name, int dso_type) | ||
2174 | { | 2270 | { |
2175 | struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); | 2271 | /* |
2176 | 2272 | * The kernel dso could be created by build_id processing. | |
2177 | if (dso != NULL) { | 2273 | */ |
2178 | dso__set_short_name(dso, "[kernel]"); | 2274 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); |
2179 | dso->kernel = DSO_TYPE_KERNEL; | ||
2180 | } | ||
2181 | |||
2182 | return dso; | ||
2183 | } | ||
2184 | 2275 | ||
2185 | static struct dso *dso__new_guest_kernel(struct machine *machine, | 2276 | /* |
2186 | const char *name) | 2277 | * We need to run this in all cases, since during the build_id |
2187 | { | 2278 | * processing we had no idea this was the kernel dso. |
2188 | char bf[PATH_MAX]; | 2279 | */ |
2189 | struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, | ||
2190 | sizeof(bf))); | ||
2191 | if (dso != NULL) { | 2280 | if (dso != NULL) { |
2192 | dso__set_short_name(dso, "[guest.kernel]"); | 2281 | dso__set_short_name(dso, short_name); |
2193 | dso->kernel = DSO_TYPE_GUEST_KERNEL; | 2282 | dso->kernel = dso_type; |
2194 | } | 2283 | } |
2195 | 2284 | ||
2196 | return dso; | 2285 | return dso; |
@@ -2208,24 +2297,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | |||
2208 | dso->has_build_id = true; | 2297 | dso->has_build_id = true; |
2209 | } | 2298 | } |
2210 | 2299 | ||
2211 | static struct dso *machine__create_kernel(struct machine *machine) | 2300 | static struct dso *machine__get_kernel(struct machine *machine) |
2212 | { | 2301 | { |
2213 | const char *vmlinux_name = NULL; | 2302 | const char *vmlinux_name = NULL; |
2214 | struct dso *kernel; | 2303 | struct dso *kernel; |
2215 | 2304 | ||
2216 | if (machine__is_host(machine)) { | 2305 | if (machine__is_host(machine)) { |
2217 | vmlinux_name = symbol_conf.vmlinux_name; | 2306 | vmlinux_name = symbol_conf.vmlinux_name; |
2218 | kernel = dso__new_kernel(vmlinux_name); | 2307 | if (!vmlinux_name) |
2308 | vmlinux_name = "[kernel.kallsyms]"; | ||
2309 | |||
2310 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2311 | "[kernel]", | ||
2312 | DSO_TYPE_KERNEL); | ||
2219 | } else { | 2313 | } else { |
2314 | char bf[PATH_MAX]; | ||
2315 | |||
2220 | if (machine__is_default_guest(machine)) | 2316 | if (machine__is_default_guest(machine)) |
2221 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 2317 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
2222 | kernel = dso__new_guest_kernel(machine, vmlinux_name); | 2318 | if (!vmlinux_name) |
2319 | vmlinux_name = machine__mmap_name(machine, bf, | ||
2320 | sizeof(bf)); | ||
2321 | |||
2322 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2323 | "[guest.kernel]", | ||
2324 | DSO_TYPE_GUEST_KERNEL); | ||
2223 | } | 2325 | } |
2224 | 2326 | ||
2225 | if (kernel != NULL) { | 2327 | if (kernel != NULL && (!kernel->has_build_id)) |
2226 | dso__read_running_kernel_build_id(kernel, machine); | 2328 | dso__read_running_kernel_build_id(kernel, machine); |
2227 | dsos__add(&machine->kernel_dsos, kernel); | 2329 | |
2228 | } | ||
2229 | return kernel; | 2330 | return kernel; |
2230 | } | 2331 | } |
2231 | 2332 | ||
@@ -2329,7 +2430,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
2329 | 2430 | ||
2330 | int machine__create_kernel_maps(struct machine *machine) | 2431 | int machine__create_kernel_maps(struct machine *machine) |
2331 | { | 2432 | { |
2332 | struct dso *kernel = machine__create_kernel(machine); | 2433 | struct dso *kernel = machine__get_kernel(machine); |
2333 | 2434 | ||
2334 | if (kernel == NULL || | 2435 | if (kernel == NULL || |
2335 | __machine__create_kernel_maps(machine, kernel) < 0) | 2436 | __machine__create_kernel_maps(machine, kernel) < 0) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 325ee36a9d29..4f377d92e75a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -155,7 +155,6 @@ struct dso { | |||
155 | }; | 155 | }; |
156 | 156 | ||
157 | struct dso *dso__new(const char *name); | 157 | struct dso *dso__new(const char *name); |
158 | struct dso *dso__new_kernel(const char *name); | ||
159 | void dso__delete(struct dso *dso); | 158 | void dso__delete(struct dso *dso); |
160 | 159 | ||
161 | int dso__name_len(const struct dso *dso); | 160 | int dso__name_len(const struct dso *dso); |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c index 5a06538532af..88403cf8396a 100644 --- a/tools/perf/util/ui/browsers/top.c +++ b/tools/perf/util/ui/browsers/top.c | |||
@@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top) | |||
208 | }, | 208 | }, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | ui_helpline__push("Press <- or ESC to exit"); | ||
212 | return perf_top_browser__run(&browser); | 211 | return perf_top_browser__run(&browser); |
213 | } | 212 | } |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 94c2cf0a98b8..e8a03aceceb1 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | # Set the following to `true' to make a unstripped, unoptimized | 25 | # Set the following to `true' to make a unstripped, unoptimized |
26 | # binary. Leave this set to `false' for production use. | 26 | # binary. Leave this set to `false' for production use. |
27 | DEBUG ?= false | 27 | DEBUG ?= true |
28 | 28 | ||
29 | # make the build silent. Set this to something else to make it noisy again. | 29 | # make the build silent. Set this to something else to make it noisy again. |
30 | V ?= false | 30 | V ?= false |
@@ -35,7 +35,7 @@ NLS ?= true | |||
35 | 35 | ||
36 | # Set the following to 'true' to build/install the | 36 | # Set the following to 'true' to build/install the |
37 | # cpufreq-bench benchmarking tool | 37 | # cpufreq-bench benchmarking tool |
38 | CPUFRQ_BENCH ?= true | 38 | CPUFREQ_BENCH ?= true |
39 | 39 | ||
40 | # Prefix to the directories we're installing to | 40 | # Prefix to the directories we're installing to |
41 | DESTDIR ?= | 41 | DESTDIR ?= |
@@ -137,9 +137,10 @@ CFLAGS += -pipe | |||
137 | ifeq ($(strip $(NLS)),true) | 137 | ifeq ($(strip $(NLS)),true) |
138 | INSTALL_NLS += install-gmo | 138 | INSTALL_NLS += install-gmo |
139 | COMPILE_NLS += create-gmo | 139 | COMPILE_NLS += create-gmo |
140 | CFLAGS += -DNLS | ||
140 | endif | 141 | endif |
141 | 142 | ||
142 | ifeq ($(strip $(CPUFRQ_BENCH)),true) | 143 | ifeq ($(strip $(CPUFREQ_BENCH)),true) |
143 | INSTALL_BENCH += install-bench | 144 | INSTALL_BENCH += install-bench |
144 | COMPILE_BENCH += compile-bench | 145 | COMPILE_BENCH += compile-bench |
145 | endif | 146 | endif |
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile index dbf13998462a..3326217dd311 100644 --- a/tools/power/cpupower/debug/x86_64/Makefile +++ b/tools/power/cpupower/debug/x86_64/Makefile | |||
@@ -1,10 +1,10 @@ | |||
1 | default: all | 1 | default: all |
2 | 2 | ||
3 | centrino-decode: centrino-decode.c | 3 | centrino-decode: ../i386/centrino-decode.c |
4 | $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c | 4 | $(CC) $(CFLAGS) -o $@ $< |
5 | 5 | ||
6 | powernow-k8-decode: powernow-k8-decode.c | 6 | powernow-k8-decode: ../i386/powernow-k8-decode.c |
7 | $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c | 7 | $(CC) $(CFLAGS) -o $@ $< |
8 | 8 | ||
9 | all: centrino-decode powernow-k8-decode | 9 | all: centrino-decode powernow-k8-decode |
10 | 10 | ||
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c deleted file mode 120000 index 26fb3f1d8fc7..000000000000 --- a/tools/power/cpupower/debug/x86_64/centrino-decode.c +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | ../i386/centrino-decode.c \ No newline at end of file | ||
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c deleted file mode 120000 index eb30c79cf9df..000000000000 --- a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | ../i386/powernow-k8-decode.c \ No newline at end of file | ||
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index 3194811d58f5..bb60a8d1e45a 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 | |||
@@ -1,10 +1,10 @@ | |||
1 | .TH "cpufreq-info" "1" "0.1" "Mattia Dongili" "" | 1 | .TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" "" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpufreq\-info \- Utility to retrieve cpufreq kernel information | 4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpufreq\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] |
8 | .SH "DESCRIPTION" | 8 | .SH "DESCRIPTION" |
9 | .LP | 9 | .LP |
10 | A small tool which prints out cpufreq information helpful to developers and interested users. | 10 | A small tool which prints out cpufreq information helpful to developers and interested users. |
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 index 26e3e13eee3b..685f469093ad 100644 --- a/tools/power/cpupower/man/cpupower-frequency-set.1 +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 | |||
@@ -1,13 +1,13 @@ | |||
1 | .TH "cpufreq-set" "1" "0.1" "Mattia Dongili" "" | 1 | .TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" "" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpufreq\-set \- A small tool which allows to modify cpufreq settings. | 4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpufreq\-set [\fIoptions\fP] | 7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] |
8 | .SH "DESCRIPTION" | 8 | .SH "DESCRIPTION" |
9 | .LP | 9 | .LP |
10 | cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. | 10 | cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. |
11 | .SH "OPTIONS" | 11 | .SH "OPTIONS" |
12 | .LP | 12 | .LP |
13 | .TP | 13 | .TP |
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1 index 78c20feab85c..baf741d06e82 100644 --- a/tools/power/cpupower/man/cpupower.1 +++ b/tools/power/cpupower/man/cpupower.1 | |||
@@ -3,7 +3,7 @@ | |||
3 | cpupower \- Shows and sets processor power related values | 3 | cpupower \- Shows and sets processor power related values |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .ft B | 5 | .ft B |
6 | .B cpupower [ \-c cpulist ] subcommand [ARGS] | 6 | .B cpupower [ \-c cpulist ] <command> [ARGS] |
7 | 7 | ||
8 | .B cpupower \-v|\-\-version | 8 | .B cpupower \-v|\-\-version |
9 | 9 | ||
@@ -13,24 +13,24 @@ cpupower \- Shows and sets processor power related values | |||
13 | \fBcpupower \fP is a collection of tools to examine and tune power saving | 13 | \fBcpupower \fP is a collection of tools to examine and tune power saving |
14 | related features of your processor. | 14 | related features of your processor. |
15 | 15 | ||
16 | The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed | 16 | The manpages of the commands (cpupower\-<command>(1)) provide detailed |
17 | descriptions of supported features. Run \fBcpupower help\fP to get an overview | 17 | descriptions of supported features. Run \fBcpupower help\fP to get an overview |
18 | of supported subcommands. | 18 | of supported commands. |
19 | 19 | ||
20 | .SH Options | 20 | .SH Options |
21 | .PP | 21 | .PP |
22 | \-\-help, \-h | 22 | \-\-help, \-h |
23 | .RS 4 | 23 | .RS 4 |
24 | Shows supported subcommands and general usage. | 24 | Shows supported commands and general usage. |
25 | .RE | 25 | .RE |
26 | .PP | 26 | .PP |
27 | \-\-cpu cpulist, \-c cpulist | 27 | \-\-cpu cpulist, \-c cpulist |
28 | .RS 4 | 28 | .RS 4 |
29 | Only show or set values for specific cores. | 29 | Only show or set values for specific cores. |
30 | This option is not supported by all subcommands, details can be found in the | 30 | This option is not supported by all commands, details can be found in the |
31 | manpages of the subcommands. | 31 | manpages of the commands. |
32 | 32 | ||
33 | Some subcommands access all cores (typically the *\-set commands), some only | 33 | Some commands access all cores (typically the *\-set commands), some only |
34 | the first core (typically the *\-info commands) by default. | 34 | the first core (typically the *\-info commands) by default. |
35 | 35 | ||
36 | The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via | 36 | The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via |
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h index c870ffba5219..c10496fbe3c6 100644 --- a/tools/power/cpupower/utils/builtin.h +++ b/tools/power/cpupower/utils/builtin.h | |||
@@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv); | |||
8 | extern int cmd_idle_info(int argc, const char **argv); | 8 | extern int cmd_idle_info(int argc, const char **argv); |
9 | extern int cmd_monitor(int argc, const char **argv); | 9 | extern int cmd_monitor(int argc, const char **argv); |
10 | 10 | ||
11 | extern void set_help(void); | ||
12 | extern void info_help(void); | ||
13 | extern void freq_set_help(void); | ||
14 | extern void freq_info_help(void); | ||
15 | extern void idle_info_help(void); | ||
16 | extern void monitor_help(void); | ||
17 | |||
18 | #endif | 11 | #endif |
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 5a1d25f056b3..28953c9a7bd5 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c | |||
@@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human) | |||
510 | return 0; | 510 | return 0; |
511 | } | 511 | } |
512 | 512 | ||
513 | void freq_info_help(void) | ||
514 | { | ||
515 | printf(_("Usage: cpupower freqinfo [options]\n")); | ||
516 | printf(_("Options:\n")); | ||
517 | printf(_(" -e, --debug Prints out debug information [default]\n")); | ||
518 | printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n" | ||
519 | " to the cpufreq core *\n")); | ||
520 | printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
521 | " it from hardware (only available to root) *\n")); | ||
522 | printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n")); | ||
523 | printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n")); | ||
524 | printf(_(" -p, --policy Gets the currently used cpufreq policy *\n")); | ||
525 | printf(_(" -g, --governors Determines available cpufreq governors *\n")); | ||
526 | printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n")); | ||
527 | printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
528 | " coordinated by software *\n")); | ||
529 | printf(_(" -s, --stats Shows cpufreq statistics if available\n")); | ||
530 | printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n")); | ||
531 | printf(_(" -b, --boost Checks for turbo or boost modes *\n")); | ||
532 | printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n" | ||
533 | " interface in 2.4. and early 2.6. kernels\n")); | ||
534 | printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n")); | ||
535 | printf(_(" -h, --help Prints out this screen\n")); | ||
536 | |||
537 | printf("\n"); | ||
538 | printf(_("If no argument is given, full output about\n" | ||
539 | "cpufreq is printed which is useful e.g. for reporting bugs.\n\n")); | ||
540 | printf(_("By default info of CPU 0 is shown which can be overridden\n" | ||
541 | "with the cpupower --cpu main command option.\n")); | ||
542 | } | ||
543 | |||
544 | static struct option info_opts[] = { | 513 | static struct option info_opts[] = { |
545 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, | 514 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, |
546 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, | 515 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, |
@@ -556,7 +525,6 @@ static struct option info_opts[] = { | |||
556 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, | 525 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, |
557 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | 526 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, |
558 | { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, | 527 | { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, |
559 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
560 | { }, | 528 | { }, |
561 | }; | 529 | }; |
562 | 530 | ||
@@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv) | |||
570 | int output_param = 0; | 538 | int output_param = 0; |
571 | 539 | ||
572 | do { | 540 | do { |
573 | ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL); | 541 | ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); |
574 | switch (ret) { | 542 | switch (ret) { |
575 | case '?': | 543 | case '?': |
576 | output_param = '?'; | 544 | output_param = '?'; |
577 | cont = 0; | 545 | cont = 0; |
578 | break; | 546 | break; |
579 | case 'h': | ||
580 | output_param = 'h'; | ||
581 | cont = 0; | ||
582 | break; | ||
583 | case -1: | 547 | case -1: |
584 | cont = 0; | 548 | cont = 0; |
585 | break; | 549 | break; |
@@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv) | |||
642 | return -EINVAL; | 606 | return -EINVAL; |
643 | case '?': | 607 | case '?': |
644 | printf(_("invalid or unknown argument\n")); | 608 | printf(_("invalid or unknown argument\n")); |
645 | freq_info_help(); | ||
646 | return -EINVAL; | 609 | return -EINVAL; |
647 | case 'h': | ||
648 | freq_info_help(); | ||
649 | return EXIT_SUCCESS; | ||
650 | case 'o': | 610 | case 'o': |
651 | proc_cpufreq_output(); | 611 | proc_cpufreq_output(); |
652 | return EXIT_SUCCESS; | 612 | return EXIT_SUCCESS; |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 5f783622bf31..dd1539eb8c63 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -20,34 +20,11 @@ | |||
20 | 20 | ||
21 | #define NORM_FREQ_LEN 32 | 21 | #define NORM_FREQ_LEN 32 |
22 | 22 | ||
23 | void freq_set_help(void) | ||
24 | { | ||
25 | printf(_("Usage: cpupower frequency-set [options]\n")); | ||
26 | printf(_("Options:\n")); | ||
27 | printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n")); | ||
28 | printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n")); | ||
29 | printf(_(" -g GOV, --governor GOV new cpufreq governor\n")); | ||
30 | printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
31 | " governor to be available and loaded\n")); | ||
32 | printf(_(" -r, --related Switches all hardware-related CPUs\n")); | ||
33 | printf(_(" -h, --help Prints out this screen\n")); | ||
34 | printf("\n"); | ||
35 | printf(_("Notes:\n" | ||
36 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n")); | ||
37 | printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n" | ||
38 | " except the -c CPU, --cpu CPU parameter\n" | ||
39 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
40 | " by postfixing the value with the wanted unit name, without any space\n" | ||
41 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n")); | ||
42 | |||
43 | } | ||
44 | |||
45 | static struct option set_opts[] = { | 23 | static struct option set_opts[] = { |
46 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, | 24 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, |
47 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, | 25 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, |
48 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, | 26 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, |
49 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, | 27 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, |
50 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
51 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, | 28 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, |
52 | { }, | 29 | { }, |
53 | }; | 30 | }; |
@@ -80,7 +57,6 @@ const struct freq_units def_units[] = { | |||
80 | static void print_unknown_arg(void) | 57 | static void print_unknown_arg(void) |
81 | { | 58 | { |
82 | printf(_("invalid or unknown argument\n")); | 59 | printf(_("invalid or unknown argument\n")); |
83 | freq_set_help(); | ||
84 | } | 60 | } |
85 | 61 | ||
86 | static unsigned long string_to_frequency(const char *str) | 62 | static unsigned long string_to_frequency(const char *str) |
@@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv) | |||
231 | 207 | ||
232 | /* parameter parsing */ | 208 | /* parameter parsing */ |
233 | do { | 209 | do { |
234 | ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL); | 210 | ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL); |
235 | switch (ret) { | 211 | switch (ret) { |
236 | case '?': | 212 | case '?': |
237 | print_unknown_arg(); | 213 | print_unknown_arg(); |
238 | return -EINVAL; | 214 | return -EINVAL; |
239 | case 'h': | ||
240 | freq_set_help(); | ||
241 | return 0; | ||
242 | case -1: | 215 | case -1: |
243 | cont = 0; | 216 | cont = 0; |
244 | break; | 217 | break; |
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 70da3574f1e9..b028267c1376 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | /* --freq / -f */ | ||
143 | |||
144 | void idle_info_help(void) | ||
145 | { | ||
146 | printf(_ ("Usage: cpupower idleinfo [options]\n")); | ||
147 | printf(_ ("Options:\n")); | ||
148 | printf(_ (" -s, --silent Only show general C-state information\n")); | ||
149 | printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n" | ||
150 | " interface in older kernels\n")); | ||
151 | printf(_ (" -h, --help Prints out this screen\n")); | ||
152 | |||
153 | printf("\n"); | ||
154 | } | ||
155 | |||
156 | static struct option info_opts[] = { | 142 | static struct option info_opts[] = { |
157 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, | 143 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, |
158 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | 144 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, |
159 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
160 | { }, | 145 | { }, |
161 | }; | 146 | }; |
162 | 147 | ||
163 | static inline void cpuidle_exit(int fail) | 148 | static inline void cpuidle_exit(int fail) |
164 | { | 149 | { |
165 | idle_info_help(); | ||
166 | exit(EXIT_FAILURE); | 150 | exit(EXIT_FAILURE); |
167 | } | 151 | } |
168 | 152 | ||
@@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv) | |||
174 | unsigned int cpu = 0; | 158 | unsigned int cpu = 0; |
175 | 159 | ||
176 | do { | 160 | do { |
177 | ret = getopt_long(argc, argv, "hos", info_opts, NULL); | 161 | ret = getopt_long(argc, argv, "os", info_opts, NULL); |
178 | if (ret == -1) | 162 | if (ret == -1) |
179 | break; | 163 | break; |
180 | switch (ret) { | 164 | switch (ret) { |
@@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv) | |||
182 | output_param = '?'; | 166 | output_param = '?'; |
183 | cont = 0; | 167 | cont = 0; |
184 | break; | 168 | break; |
185 | case 'h': | ||
186 | output_param = 'h'; | ||
187 | cont = 0; | ||
188 | break; | ||
189 | case 's': | 169 | case 's': |
190 | verbose = 0; | 170 | verbose = 0; |
191 | break; | 171 | break; |
@@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv) | |||
211 | case '?': | 191 | case '?': |
212 | printf(_("invalid or unknown argument\n")); | 192 | printf(_("invalid or unknown argument\n")); |
213 | cpuidle_exit(EXIT_FAILURE); | 193 | cpuidle_exit(EXIT_FAILURE); |
214 | case 'h': | ||
215 | cpuidle_exit(EXIT_SUCCESS); | ||
216 | } | 194 | } |
217 | 195 | ||
218 | /* Default is: show output of CPU 0 only */ | 196 | /* Default is: show output of CPU 0 only */ |
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 85253cb7600e..3f68632c28c7 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c | |||
@@ -16,31 +16,16 @@ | |||
16 | #include "helpers/helpers.h" | 16 | #include "helpers/helpers.h" |
17 | #include "helpers/sysfs.h" | 17 | #include "helpers/sysfs.h" |
18 | 18 | ||
19 | void info_help(void) | ||
20 | { | ||
21 | printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n")); | ||
22 | printf(_("Options:\n")); | ||
23 | printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
24 | " Intel models [0-15], see manpage for details\n")); | ||
25 | printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n")); | ||
26 | printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n")); | ||
27 | printf(_(" -h, --help Prints out this screen\n")); | ||
28 | printf(_("\nPassing no option will show all info, by default only on core 0\n")); | ||
29 | printf("\n"); | ||
30 | } | ||
31 | |||
32 | static struct option set_opts[] = { | 19 | static struct option set_opts[] = { |
33 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | 20 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | 21 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | 22 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, |
36 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
37 | { }, | 23 | { }, |
38 | }; | 24 | }; |
39 | 25 | ||
40 | static void print_wrong_arg_exit(void) | 26 | static void print_wrong_arg_exit(void) |
41 | { | 27 | { |
42 | printf(_("invalid or unknown argument\n")); | 28 | printf(_("invalid or unknown argument\n")); |
43 | info_help(); | ||
44 | exit(EXIT_FAILURE); | 29 | exit(EXIT_FAILURE); |
45 | } | 30 | } |
46 | 31 | ||
@@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv) | |||
64 | textdomain(PACKAGE); | 49 | textdomain(PACKAGE); |
65 | 50 | ||
66 | /* parameter parsing */ | 51 | /* parameter parsing */ |
67 | while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) { | 52 | while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) { |
68 | switch (ret) { | 53 | switch (ret) { |
69 | case 'h': | ||
70 | info_help(); | ||
71 | return 0; | ||
72 | case 'b': | 54 | case 'b': |
73 | if (params.perf_bias) | 55 | if (params.perf_bias) |
74 | print_wrong_arg_exit(); | 56 | print_wrong_arg_exit(); |
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index bc1b391e46f0..dc4de3762111 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c | |||
@@ -17,30 +17,16 @@ | |||
17 | #include "helpers/sysfs.h" | 17 | #include "helpers/sysfs.h" |
18 | #include "helpers/bitmask.h" | 18 | #include "helpers/bitmask.h" |
19 | 19 | ||
20 | void set_help(void) | ||
21 | { | ||
22 | printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n")); | ||
23 | printf(_("Options:\n")); | ||
24 | printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
25 | " Intel models [0-15], see manpage for details\n")); | ||
26 | printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n")); | ||
27 | printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n")); | ||
28 | printf(_(" -h, --help Prints out this screen\n")); | ||
29 | printf("\n"); | ||
30 | } | ||
31 | |||
32 | static struct option set_opts[] = { | 20 | static struct option set_opts[] = { |
33 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | 21 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, |
34 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | 22 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, |
35 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | 23 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, |
36 | { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'}, | ||
37 | { }, | 24 | { }, |
38 | }; | 25 | }; |
39 | 26 | ||
40 | static void print_wrong_arg_exit(void) | 27 | static void print_wrong_arg_exit(void) |
41 | { | 28 | { |
42 | printf(_("invalid or unknown argument\n")); | 29 | printf(_("invalid or unknown argument\n")); |
43 | set_help(); | ||
44 | exit(EXIT_FAILURE); | 30 | exit(EXIT_FAILURE); |
45 | } | 31 | } |
46 | 32 | ||
@@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv) | |||
66 | 52 | ||
67 | params.params = 0; | 53 | params.params = 0; |
68 | /* parameter parsing */ | 54 | /* parameter parsing */ |
69 | while ((ret = getopt_long(argc, argv, "m:s:b:h", | 55 | while ((ret = getopt_long(argc, argv, "m:s:b:", |
70 | set_opts, NULL)) != -1) { | 56 | set_opts, NULL)) != -1) { |
71 | switch (ret) { | 57 | switch (ret) { |
72 | case 'h': | ||
73 | set_help(); | ||
74 | return 0; | ||
75 | case 'b': | 58 | case 'b': |
76 | if (params.perf_bias) | 59 | if (params.perf_bias) |
77 | print_wrong_arg_exit(); | 60 | print_wrong_arg_exit(); |
@@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv) | |||
110 | } | 93 | } |
111 | }; | 94 | }; |
112 | 95 | ||
113 | if (!params.params) { | 96 | if (!params.params) |
114 | set_help(); | 97 | print_wrong_arg_exit(); |
115 | return -EINVAL; | ||
116 | } | ||
117 | 98 | ||
118 | if (params.sched_mc) { | 99 | if (params.sched_mc) { |
119 | ret = sysfs_set_sched("mc", sched_mc); | 100 | ret = sysfs_set_sched("mc", sched_mc); |
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 5844ae0f786f..52bee591c1c5 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | #include <string.h> | 12 | #include <string.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <errno.h> | ||
14 | 15 | ||
15 | #include "builtin.h" | 16 | #include "builtin.h" |
16 | #include "helpers/helpers.h" | 17 | #include "helpers/helpers.h" |
@@ -19,13 +20,12 @@ | |||
19 | struct cmd_struct { | 20 | struct cmd_struct { |
20 | const char *cmd; | 21 | const char *cmd; |
21 | int (*main)(int, const char **); | 22 | int (*main)(int, const char **); |
22 | void (*usage)(void); | ||
23 | int needs_root; | 23 | int needs_root; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | 26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
27 | 27 | ||
28 | int cmd_help(int argc, const char **argv); | 28 | static int cmd_help(int argc, const char **argv); |
29 | 29 | ||
30 | /* Global cpu_info object available for all binaries | 30 | /* Global cpu_info object available for all binaries |
31 | * Info only retrieved from CPU 0 | 31 | * Info only retrieved from CPU 0 |
@@ -44,55 +44,66 @@ int be_verbose; | |||
44 | static void print_help(void); | 44 | static void print_help(void); |
45 | 45 | ||
46 | static struct cmd_struct commands[] = { | 46 | static struct cmd_struct commands[] = { |
47 | { "frequency-info", cmd_freq_info, freq_info_help, 0 }, | 47 | { "frequency-info", cmd_freq_info, 0 }, |
48 | { "frequency-set", cmd_freq_set, freq_set_help, 1 }, | 48 | { "frequency-set", cmd_freq_set, 1 }, |
49 | { "idle-info", cmd_idle_info, idle_info_help, 0 }, | 49 | { "idle-info", cmd_idle_info, 0 }, |
50 | { "set", cmd_set, set_help, 1 }, | 50 | { "set", cmd_set, 1 }, |
51 | { "info", cmd_info, info_help, 0 }, | 51 | { "info", cmd_info, 0 }, |
52 | { "monitor", cmd_monitor, monitor_help, 0 }, | 52 | { "monitor", cmd_monitor, 0 }, |
53 | { "help", cmd_help, print_help, 0 }, | 53 | { "help", cmd_help, 0 }, |
54 | /* { "bench", cmd_bench, NULL, 1 }, */ | 54 | /* { "bench", cmd_bench, 1 }, */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | int cmd_help(int argc, const char **argv) | ||
58 | { | ||
59 | unsigned int i; | ||
60 | |||
61 | if (argc > 1) { | ||
62 | for (i = 0; i < ARRAY_SIZE(commands); i++) { | ||
63 | struct cmd_struct *p = commands + i; | ||
64 | if (strcmp(p->cmd, argv[1])) | ||
65 | continue; | ||
66 | if (p->usage) { | ||
67 | p->usage(); | ||
68 | return EXIT_SUCCESS; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | print_help(); | ||
73 | if (argc == 1) | ||
74 | return EXIT_SUCCESS; /* cpupower help */ | ||
75 | return EXIT_FAILURE; | ||
76 | } | ||
77 | |||
78 | static void print_help(void) | 57 | static void print_help(void) |
79 | { | 58 | { |
80 | unsigned int i; | 59 | unsigned int i; |
81 | 60 | ||
82 | #ifdef DEBUG | 61 | #ifdef DEBUG |
83 | printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n")); | 62 | printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); |
84 | printf(_(" -d, --debug May increase output (stderr) on some subcommands\n")); | ||
85 | #else | 63 | #else |
86 | printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n")); | 64 | printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); |
87 | #endif | 65 | #endif |
88 | printf(_("cpupower --version\n")); | 66 | printf(_("Supported commands are:\n")); |
89 | printf(_("Supported subcommands are:\n")); | ||
90 | for (i = 0; i < ARRAY_SIZE(commands); i++) | 67 | for (i = 0; i < ARRAY_SIZE(commands); i++) |
91 | printf("\t%s\n", commands[i].cmd); | 68 | printf("\t%s\n", commands[i].cmd); |
92 | printf(_("\nSome subcommands can make use of the -c cpulist option.\n")); | 69 | printf(_("\nNot all commands can make use of the -c cpulist option.\n")); |
93 | printf(_("Look at the general cpupower manpage how to use it\n")); | 70 | printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); |
94 | printf(_("and read up the subcommand's manpage whether it is supported.\n")); | 71 | } |
95 | printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n")); | 72 | |
73 | static int print_man_page(const char *subpage) | ||
74 | { | ||
75 | int len; | ||
76 | char *page; | ||
77 | |||
78 | len = 10; /* enough for "cpupower-" */ | ||
79 | if (subpage != NULL) | ||
80 | len += strlen(subpage); | ||
81 | |||
82 | page = malloc(len); | ||
83 | if (!page) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | sprintf(page, "cpupower"); | ||
87 | if ((subpage != NULL) && strcmp(subpage, "help")) { | ||
88 | strcat(page, "-"); | ||
89 | strcat(page, subpage); | ||
90 | } | ||
91 | |||
92 | execlp("man", "man", page, NULL); | ||
93 | |||
94 | /* should not be reached */ | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | |||
98 | static int cmd_help(int argc, const char **argv) | ||
99 | { | ||
100 | if (argc > 1) { | ||
101 | print_man_page(argv[1]); /* exits within execlp() */ | ||
102 | return EXIT_FAILURE; | ||
103 | } | ||
104 | |||
105 | print_help(); | ||
106 | return EXIT_SUCCESS; | ||
96 | } | 107 | } |
97 | 108 | ||
98 | static void print_version(void) | 109 | static void print_version(void) |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 592ee362b877..2747e738efb0 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -16,11 +16,20 @@ | |||
16 | #include "helpers/bitmask.h" | 16 | #include "helpers/bitmask.h" |
17 | 17 | ||
18 | /* Internationalization ****************************/ | 18 | /* Internationalization ****************************/ |
19 | #ifdef NLS | ||
20 | |||
19 | #define _(String) gettext(String) | 21 | #define _(String) gettext(String) |
20 | #ifndef gettext_noop | 22 | #ifndef gettext_noop |
21 | #define gettext_noop(String) String | 23 | #define gettext_noop(String) String |
22 | #endif | 24 | #endif |
23 | #define N_(String) gettext_noop(String) | 25 | #define N_(String) gettext_noop(String) |
26 | |||
27 | #else /* !NLS */ | ||
28 | |||
29 | #define _(String) String | ||
30 | #define N_(String) String | ||
31 | |||
32 | #endif | ||
24 | /* Internationalization ****************************/ | 33 | /* Internationalization ****************************/ |
25 | 34 | ||
26 | extern int run_as_root; | 35 | extern int run_as_root; |
@@ -96,6 +105,9 @@ struct cpupower_topology { | |||
96 | int pkg; | 105 | int pkg; |
97 | int core; | 106 | int core; |
98 | int cpu; | 107 | int cpu; |
108 | |||
109 | /* flags */ | ||
110 | unsigned int is_online:1; | ||
99 | } *core_info; | 111 | } *core_info; |
100 | }; | 112 | }; |
101 | 113 | ||
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 55e2466674c6..c6343024a611 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c | |||
@@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path, | |||
56 | return (unsigned int) numwrite; | 56 | return (unsigned int) numwrite; |
57 | } | 57 | } |
58 | 58 | ||
59 | /* | ||
60 | * Detect whether a CPU is online | ||
61 | * | ||
62 | * Returns: | ||
63 | * 1 -> if CPU is online | ||
64 | * 0 -> if CPU is offline | ||
65 | * negative errno values in error case | ||
66 | */ | ||
67 | int sysfs_is_cpu_online(unsigned int cpu) | ||
68 | { | ||
69 | char path[SYSFS_PATH_MAX]; | ||
70 | int fd; | ||
71 | ssize_t numread; | ||
72 | unsigned long long value; | ||
73 | char linebuf[MAX_LINE_LEN]; | ||
74 | char *endp; | ||
75 | struct stat statbuf; | ||
76 | |||
77 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); | ||
78 | |||
79 | if (stat(path, &statbuf) != 0) | ||
80 | return 0; | ||
81 | |||
82 | /* | ||
83 | * kernel without CONFIG_HOTPLUG_CPU | ||
84 | * -> cpuX directory exists, but not cpuX/online file | ||
85 | */ | ||
86 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); | ||
87 | if (stat(path, &statbuf) != 0) | ||
88 | return 1; | ||
89 | |||
90 | fd = open(path, O_RDONLY); | ||
91 | if (fd == -1) | ||
92 | return -errno; | ||
93 | |||
94 | numread = read(fd, linebuf, MAX_LINE_LEN - 1); | ||
95 | if (numread < 1) { | ||
96 | close(fd); | ||
97 | return -EIO; | ||
98 | } | ||
99 | linebuf[numread] = '\0'; | ||
100 | close(fd); | ||
101 | |||
102 | value = strtoull(linebuf, &endp, 0); | ||
103 | if (value > 1 || value < 0) | ||
104 | return -EINVAL; | ||
105 | |||
106 | return value; | ||
107 | } | ||
108 | |||
59 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | 109 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ |
60 | 110 | ||
61 | /* | 111 | /* |
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h index f9373e090637..8cb797bbceb0 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.h +++ b/tools/power/cpupower/utils/helpers/sysfs.h | |||
@@ -7,6 +7,8 @@ | |||
7 | 7 | ||
8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | 8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); |
9 | 9 | ||
10 | extern int sysfs_is_cpu_online(unsigned int cpu); | ||
11 | |||
10 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | 12 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, |
11 | unsigned int idlestate); | 13 | unsigned int idlestate); |
12 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, | 14 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, |
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 385ee5c7570c..4eae2c47ba48 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -41,6 +41,8 @@ struct cpuid_core_info { | |||
41 | unsigned int pkg; | 41 | unsigned int pkg; |
42 | unsigned int thread; | 42 | unsigned int thread; |
43 | unsigned int cpu; | 43 | unsigned int cpu; |
44 | /* flags */ | ||
45 | unsigned int is_online:1; | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | static int __compare(const void *t1, const void *t2) | 48 | static int __compare(const void *t1, const void *t2) |
@@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) | |||
78 | return -ENOMEM; | 80 | return -ENOMEM; |
79 | cpu_top->pkgs = cpu_top->cores = 0; | 81 | cpu_top->pkgs = cpu_top->cores = 0; |
80 | for (cpu = 0; cpu < cpus; cpu++) { | 82 | for (cpu = 0; cpu < cpus; cpu++) { |
83 | cpu_top->core_info[cpu].cpu = cpu; | ||
84 | cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); | ||
81 | cpu_top->core_info[cpu].pkg = | 85 | cpu_top->core_info[cpu].pkg = |
82 | sysfs_topology_read_file(cpu, "physical_package_id"); | 86 | sysfs_topology_read_file(cpu, "physical_package_id"); |
83 | if ((int)cpu_top->core_info[cpu].pkg != -1 && | 87 | if ((int)cpu_top->core_info[cpu].pkg != -1 && |
@@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) | |||
85 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; | 89 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; |
86 | cpu_top->core_info[cpu].core = | 90 | cpu_top->core_info[cpu].core = |
87 | sysfs_topology_read_file(cpu, "core_id"); | 91 | sysfs_topology_read_file(cpu, "core_id"); |
88 | cpu_top->core_info[cpu].cpu = cpu; | ||
89 | } | 92 | } |
90 | cpu_top->pkgs++; | 93 | cpu_top->pkgs++; |
91 | 94 | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index d048b96a6155..bcd22a1a3970 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
134 | /* Assume idle state count is the same for all CPUs */ | 134 | /* Assume idle state count is the same for all CPUs */ |
135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); | 135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); |
136 | 136 | ||
137 | if (cpuidle_sysfs_monitor.hw_states_num == 0) | 137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) |
138 | return NULL; | 138 | return NULL; |
139 | 139 | ||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | 140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index ba4bf068380d..0d6571e418db 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c | |||
@@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top; | |||
43 | /* ToDo: Document this in the manpage */ | 43 | /* ToDo: Document this in the manpage */ |
44 | static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; | 44 | static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; |
45 | 45 | ||
46 | static void print_wrong_arg_exit(void) | ||
47 | { | ||
48 | printf(_("invalid or unknown argument\n")); | ||
49 | exit(EXIT_FAILURE); | ||
50 | } | ||
51 | |||
46 | long long timespec_diff_us(struct timespec start, struct timespec end) | 52 | long long timespec_diff_us(struct timespec start, struct timespec end) |
47 | { | 53 | { |
48 | struct timespec temp; | 54 | struct timespec temp; |
@@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end) | |||
56 | return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); | 62 | return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); |
57 | } | 63 | } |
58 | 64 | ||
59 | void monitor_help(void) | ||
60 | { | ||
61 | printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n")); | ||
62 | printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n")); | ||
63 | printf(_("cpupower monitor: -l\n")); | ||
64 | printf(_("\t command: pass an arbitrary command to measure specific workload\n")); | ||
65 | printf(_("\t -i: time intervall to measure for in seconds (default 1)\n")); | ||
66 | printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n")); | ||
67 | printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n")); | ||
68 | printf(_("\t -h: print this help\n")); | ||
69 | printf("\n"); | ||
70 | printf(_("only one of: -l, -m are allowed\nIf none of them is passed,")); | ||
71 | printf(_(" all supported monitors are shown\n")); | ||
72 | } | ||
73 | |||
74 | void print_n_spaces(int n) | 65 | void print_n_spaces(int n) |
75 | { | 66 | { |
76 | int x; | 67 | int x; |
@@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu) | |||
149 | unsigned long long result; | 140 | unsigned long long result; |
150 | cstate_t s; | 141 | cstate_t s; |
151 | 142 | ||
143 | /* Be careful CPUs may got resorted for pkg value do not just use cpu */ | ||
144 | if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) | ||
145 | return; | ||
146 | |||
152 | if (topology_depth > 2) | 147 | if (topology_depth > 2) |
153 | printf("%4d|", cpu_top.core_info[cpu].pkg); | 148 | printf("%4d|", cpu_top.core_info[cpu].pkg); |
154 | if (topology_depth > 1) | 149 | if (topology_depth > 1) |
@@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu) | |||
190 | } | 185 | } |
191 | } | 186 | } |
192 | } | 187 | } |
193 | /* cpu offline */ | 188 | /* |
194 | if (cpu_top.core_info[cpu].pkg == -1 || | 189 | * The monitor could still provide useful data, for example |
195 | cpu_top.core_info[cpu].core == -1) { | 190 | * AMD HW counters partly sit in PCI config space. |
191 | * It's up to the monitor plug-in to check .is_online, this one | ||
192 | * is just for additional info. | ||
193 | */ | ||
194 | if (!cpu_top.core_info[cpu].is_online) { | ||
196 | printf(_(" *is offline\n")); | 195 | printf(_(" *is offline\n")); |
197 | return; | 196 | return; |
198 | } else | 197 | } else |
@@ -238,7 +237,6 @@ static void parse_monitor_param(char *param) | |||
238 | if (hits == 0) { | 237 | if (hits == 0) { |
239 | printf(_("No matching monitor found in %s, " | 238 | printf(_("No matching monitor found in %s, " |
240 | "try -l option\n"), param); | 239 | "try -l option\n"), param); |
241 | monitor_help(); | ||
242 | exit(EXIT_FAILURE); | 240 | exit(EXIT_FAILURE); |
243 | } | 241 | } |
244 | /* Override detected/registerd monitors array with requested one */ | 242 | /* Override detected/registerd monitors array with requested one */ |
@@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[]) | |||
335 | int opt; | 333 | int opt; |
336 | progname = basename(argv[0]); | 334 | progname = basename(argv[0]); |
337 | 335 | ||
338 | while ((opt = getopt(argc, argv, "+hli:m:")) != -1) { | 336 | while ((opt = getopt(argc, argv, "+li:m:")) != -1) { |
339 | switch (opt) { | 337 | switch (opt) { |
340 | case 'h': | ||
341 | monitor_help(); | ||
342 | exit(EXIT_SUCCESS); | ||
343 | case 'l': | 338 | case 'l': |
344 | if (mode) { | 339 | if (mode) |
345 | monitor_help(); | 340 | print_wrong_arg_exit(); |
346 | exit(EXIT_FAILURE); | ||
347 | } | ||
348 | mode = list; | 341 | mode = list; |
349 | break; | 342 | break; |
350 | case 'i': | 343 | case 'i': |
351 | /* only allow -i with -m or no option */ | 344 | /* only allow -i with -m or no option */ |
352 | if (mode && mode != show) { | 345 | if (mode && mode != show) |
353 | monitor_help(); | 346 | print_wrong_arg_exit(); |
354 | exit(EXIT_FAILURE); | ||
355 | } | ||
356 | interval = atoi(optarg); | 347 | interval = atoi(optarg); |
357 | break; | 348 | break; |
358 | case 'm': | 349 | case 'm': |
359 | if (mode) { | 350 | if (mode) |
360 | monitor_help(); | 351 | print_wrong_arg_exit(); |
361 | exit(EXIT_FAILURE); | ||
362 | } | ||
363 | mode = show; | 352 | mode = show; |
364 | show_monitors_param = optarg; | 353 | show_monitors_param = optarg; |
365 | break; | 354 | break; |
366 | default: | 355 | default: |
367 | monitor_help(); | 356 | print_wrong_arg_exit(); |
368 | exit(EXIT_FAILURE); | ||
369 | } | 357 | } |
370 | } | 358 | } |
371 | if (!mode) | 359 | if (!mode) |
@@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv) | |||
385 | return EXIT_FAILURE; | 373 | return EXIT_FAILURE; |
386 | } | 374 | } |
387 | 375 | ||
376 | /* Default is: monitor all CPUs */ | ||
377 | if (bitmask_isallclear(cpus_chosen)) | ||
378 | bitmask_setall(cpus_chosen); | ||
379 | |||
388 | dprint("System has up to %d CPU cores\n", cpu_count); | 380 | dprint("System has up to %d CPU cores\n", cpu_count); |
389 | 381 | ||
390 | for (num = 0; all_monitors[num]; num++) { | 382 | for (num = 0; all_monitors[num]; num++) { |
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c index 63ca87a05e5f..5650ab5a2c20 100644 --- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | |||
@@ -22,12 +22,15 @@ | |||
22 | 22 | ||
23 | #define MSR_TSC 0x10 | 23 | #define MSR_TSC 0x10 |
24 | 24 | ||
25 | #define MSR_AMD_HWCR 0xc0010015 | ||
26 | |||
25 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; | 27 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; |
26 | 28 | ||
27 | static int mperf_get_count_percent(unsigned int self_id, double *percent, | 29 | static int mperf_get_count_percent(unsigned int self_id, double *percent, |
28 | unsigned int cpu); | 30 | unsigned int cpu); |
29 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 31 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
30 | unsigned int cpu); | 32 | unsigned int cpu); |
33 | static struct timespec time_start, time_end; | ||
31 | 34 | ||
32 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | 35 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { |
33 | { | 36 | { |
@@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | |||
54 | }, | 57 | }, |
55 | }; | 58 | }; |
56 | 59 | ||
60 | enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; | ||
61 | static int max_freq_mode; | ||
62 | /* | ||
63 | * The max frequency mperf is ticking at (in C0), either retrieved via: | ||
64 | * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency | ||
65 | * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time | ||
66 | * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) | ||
67 | */ | ||
68 | static unsigned long max_frequency; | ||
69 | |||
57 | static unsigned long long tsc_at_measure_start; | 70 | static unsigned long long tsc_at_measure_start; |
58 | static unsigned long long tsc_at_measure_end; | 71 | static unsigned long long tsc_at_measure_end; |
59 | static unsigned long max_frequency; | ||
60 | static unsigned long long *mperf_previous_count; | 72 | static unsigned long long *mperf_previous_count; |
61 | static unsigned long long *aperf_previous_count; | 73 | static unsigned long long *aperf_previous_count; |
62 | static unsigned long long *mperf_current_count; | 74 | static unsigned long long *mperf_current_count; |
63 | static unsigned long long *aperf_current_count; | 75 | static unsigned long long *aperf_current_count; |
76 | |||
64 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | 77 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ |
65 | static int *is_valid; | 78 | static int *is_valid; |
66 | 79 | ||
67 | static int mperf_get_tsc(unsigned long long *tsc) | 80 | static int mperf_get_tsc(unsigned long long *tsc) |
68 | { | 81 | { |
69 | return read_msr(0, MSR_TSC, tsc); | 82 | int ret; |
83 | ret = read_msr(0, MSR_TSC, tsc); | ||
84 | if (ret) | ||
85 | dprint("Reading TSC MSR failed, returning %llu\n", *tsc); | ||
86 | return ret; | ||
70 | } | 87 | } |
71 | 88 | ||
72 | static int mperf_init_stats(unsigned int cpu) | 89 | static int mperf_init_stats(unsigned int cpu) |
@@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu) | |||
97 | return 0; | 114 | return 0; |
98 | } | 115 | } |
99 | 116 | ||
100 | /* | ||
101 | * get_average_perf() | ||
102 | * | ||
103 | * Returns the average performance (also considers boosted frequencies) | ||
104 | * | ||
105 | * Input: | ||
106 | * aperf_diff: Difference of the aperf register over a time period | ||
107 | * mperf_diff: Difference of the mperf register over the same time period | ||
108 | * max_freq: Maximum frequency (P0) | ||
109 | * | ||
110 | * Returns: | ||
111 | * Average performance over the time period | ||
112 | */ | ||
113 | static unsigned long get_average_perf(unsigned long long aperf_diff, | ||
114 | unsigned long long mperf_diff) | ||
115 | { | ||
116 | unsigned int perf_percent = 0; | ||
117 | if (((unsigned long)(-1) / 100) < aperf_diff) { | ||
118 | int shift_count = 7; | ||
119 | aperf_diff >>= shift_count; | ||
120 | mperf_diff >>= shift_count; | ||
121 | } | ||
122 | perf_percent = (aperf_diff * 100) / mperf_diff; | ||
123 | return (max_frequency * perf_percent) / 100; | ||
124 | } | ||
125 | |||
126 | static int mperf_get_count_percent(unsigned int id, double *percent, | 117 | static int mperf_get_count_percent(unsigned int id, double *percent, |
127 | unsigned int cpu) | 118 | unsigned int cpu) |
128 | { | 119 | { |
129 | unsigned long long aperf_diff, mperf_diff, tsc_diff; | 120 | unsigned long long aperf_diff, mperf_diff, tsc_diff; |
121 | unsigned long long timediff; | ||
130 | 122 | ||
131 | if (!is_valid[cpu]) | 123 | if (!is_valid[cpu]) |
132 | return -1; | 124 | return -1; |
@@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent, | |||
136 | 128 | ||
137 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 129 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
138 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 130 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
139 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | ||
140 | 131 | ||
141 | *percent = 100.0 * mperf_diff / tsc_diff; | 132 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
142 | dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", | 133 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
143 | mperf_cstates[id].name, mperf_diff, tsc_diff); | 134 | *percent = 100.0 * mperf_diff / tsc_diff; |
135 | dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", | ||
136 | mperf_cstates[id].name, mperf_diff, tsc_diff); | ||
137 | } else if (max_freq_mode == MAX_FREQ_SYSFS) { | ||
138 | timediff = timespec_diff_us(time_start, time_end); | ||
139 | *percent = 100.0 * mperf_diff / timediff; | ||
140 | dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", | ||
141 | mperf_cstates[id].name, mperf_diff, timediff); | ||
142 | } else | ||
143 | return -1; | ||
144 | 144 | ||
145 | if (id == Cx) | 145 | if (id == Cx) |
146 | *percent = 100.0 - *percent; | 146 | *percent = 100.0 - *percent; |
@@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent, | |||
154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
155 | unsigned int cpu) | 155 | unsigned int cpu) |
156 | { | 156 | { |
157 | unsigned long long aperf_diff, mperf_diff; | 157 | unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff; |
158 | 158 | ||
159 | if (id != AVG_FREQ) | 159 | if (id != AVG_FREQ) |
160 | return 1; | 160 | return 1; |
@@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | |||
165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
167 | 167 | ||
168 | /* Return MHz for now, might want to return KHz if column width is more | 168 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
169 | generic */ | 169 | /* Calculate max_freq from TSC count */ |
170 | *count = get_average_perf(aperf_diff, mperf_diff) / 1000; | 170 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
171 | dprint("%s: %llu\n", mperf_cstates[id].name, *count); | 171 | time_diff = timespec_diff_us(time_start, time_end); |
172 | max_frequency = tsc_diff / time_diff; | ||
173 | } | ||
172 | 174 | ||
175 | *count = max_frequency * ((double)aperf_diff / mperf_diff); | ||
176 | dprint("%s: Average freq based on %s maximum frequency:\n", | ||
177 | mperf_cstates[id].name, | ||
178 | (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); | ||
179 | dprint("%max_frequency: %lu", max_frequency); | ||
180 | dprint("aperf_diff: %llu\n", aperf_diff); | ||
181 | dprint("mperf_diff: %llu\n", mperf_diff); | ||
182 | dprint("avg freq: %llu\n", *count); | ||
173 | return 0; | 183 | return 0; |
174 | } | 184 | } |
175 | 185 | ||
@@ -178,6 +188,7 @@ static int mperf_start(void) | |||
178 | int cpu; | 188 | int cpu; |
179 | unsigned long long dbg; | 189 | unsigned long long dbg; |
180 | 190 | ||
191 | clock_gettime(CLOCK_REALTIME, &time_start); | ||
181 | mperf_get_tsc(&tsc_at_measure_start); | 192 | mperf_get_tsc(&tsc_at_measure_start); |
182 | 193 | ||
183 | for (cpu = 0; cpu < cpu_count; cpu++) | 194 | for (cpu = 0; cpu < cpu_count; cpu++) |
@@ -193,32 +204,104 @@ static int mperf_stop(void) | |||
193 | unsigned long long dbg; | 204 | unsigned long long dbg; |
194 | int cpu; | 205 | int cpu; |
195 | 206 | ||
196 | mperf_get_tsc(&tsc_at_measure_end); | ||
197 | |||
198 | for (cpu = 0; cpu < cpu_count; cpu++) | 207 | for (cpu = 0; cpu < cpu_count; cpu++) |
199 | mperf_measure_stats(cpu); | 208 | mperf_measure_stats(cpu); |
200 | 209 | ||
210 | mperf_get_tsc(&tsc_at_measure_end); | ||
211 | clock_gettime(CLOCK_REALTIME, &time_end); | ||
212 | |||
201 | mperf_get_tsc(&dbg); | 213 | mperf_get_tsc(&dbg); |
202 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | 214 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); |
203 | 215 | ||
204 | return 0; | 216 | return 0; |
205 | } | 217 | } |
206 | 218 | ||
207 | struct cpuidle_monitor mperf_monitor; | 219 | /* |
208 | 220 | * Mperf register is defined to tick at P0 (maximum) frequency | |
209 | struct cpuidle_monitor *mperf_register(void) | 221 | * |
222 | * Instead of reading out P0 which can be tricky to read out from HW, | ||
223 | * we use TSC counter if it reliably ticks at P0/mperf frequency. | ||
224 | * | ||
225 | * Still try to fall back to: | ||
226 | * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq | ||
227 | * on older Intel HW without invariant TSC feature. | ||
228 | * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but | ||
229 | * it's still double checked (MSR_AMD_HWCR)). | ||
230 | * | ||
231 | * On these machines the user would still get useful mperf | ||
232 | * stats when acpi-cpufreq driver is loaded. | ||
233 | */ | ||
234 | static int init_maxfreq_mode(void) | ||
210 | { | 235 | { |
236 | int ret; | ||
237 | unsigned long long hwcr; | ||
211 | unsigned long min; | 238 | unsigned long min; |
212 | 239 | ||
213 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | 240 | if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) |
214 | return NULL; | 241 | goto use_sysfs; |
215 | 242 | ||
216 | /* Assume min/max all the same on all cores */ | 243 | if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { |
244 | /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf | ||
245 | * freq. | ||
246 | * A test whether hwcr is accessable/available would be: | ||
247 | * (cpupower_cpu_info.family > 0x10 || | ||
248 | * cpupower_cpu_info.family == 0x10 && | ||
249 | * cpupower_cpu_info.model >= 0x2)) | ||
250 | * This should be the case for all aperf/mperf | ||
251 | * capable AMD machines and is therefore safe to test here. | ||
252 | * Compare with Linus kernel git commit: acf01734b1747b1ec4 | ||
253 | */ | ||
254 | ret = read_msr(0, MSR_AMD_HWCR, &hwcr); | ||
255 | /* | ||
256 | * If the MSR read failed, assume a Xen system that did | ||
257 | * not explicitly provide access to it and assume TSC works | ||
258 | */ | ||
259 | if (ret != 0) { | ||
260 | dprint("TSC read 0x%x failed - assume TSC working\n", | ||
261 | MSR_AMD_HWCR); | ||
262 | return 0; | ||
263 | } else if (1 & (hwcr >> 24)) { | ||
264 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
265 | return 0; | ||
266 | } else { /* Use sysfs max frequency if available */ } | ||
267 | } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { | ||
268 | /* | ||
269 | * On Intel we assume mperf (in C0) is ticking at same | ||
270 | * rate than TSC | ||
271 | */ | ||
272 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
273 | return 0; | ||
274 | } | ||
275 | use_sysfs: | ||
217 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { | 276 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { |
218 | dprint("Cannot retrieve max freq from cpufreq kernel " | 277 | dprint("Cannot retrieve max freq from cpufreq kernel " |
219 | "subsystem\n"); | 278 | "subsystem\n"); |
220 | return NULL; | 279 | return -1; |
221 | } | 280 | } |
281 | max_freq_mode = MAX_FREQ_SYSFS; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * This monitor provides: | ||
287 | * | ||
288 | * 1) Average frequency a CPU resided in | ||
289 | * This always works if the CPU has aperf/mperf capabilities | ||
290 | * | ||
291 | * 2) C0 and Cx (any sleep state) time a CPU resided in | ||
292 | * Works if mperf timer stops ticking in sleep states which | ||
293 | * seem to be the case on all current HW. | ||
294 | * Both is directly retrieved from HW registers and is independent | ||
295 | * from kernel statistics. | ||
296 | */ | ||
297 | struct cpuidle_monitor mperf_monitor; | ||
298 | struct cpuidle_monitor *mperf_register(void) | ||
299 | { | ||
300 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | ||
301 | return NULL; | ||
302 | |||
303 | if (init_maxfreq_mode()) | ||
304 | return NULL; | ||
222 | 305 | ||
223 | /* Free this at program termination */ | 306 | /* Free this at program termination */ |
224 | is_valid = calloc(cpu_count, sizeof(int)); | 307 | is_valid = calloc(cpu_count, sizeof(int)); |