aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/.gitignore1
-rw-r--r--tools/lib/traceevent/Makefile14
-rw-r--r--tools/perf/Makefile11
-rw-r--r--tools/perf/builtin-record.c4
-rw-r--r--tools/perf/builtin-report.c5
-rw-r--r--tools/perf/builtin-test.c23
-rw-r--r--tools/perf/builtin-top.c25
-rw-r--r--tools/perf/ui/browsers/hists.c4
-rw-r--r--tools/perf/util/annotate.c15
-rw-r--r--tools/perf/util/dso-test-data.c153
-rw-r--r--tools/perf/util/event.h3
-rw-r--r--tools/perf/util/evlist.c9
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c15
-rw-r--r--tools/perf/util/evsel.h10
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/hist.c7
-rw-r--r--tools/perf/util/intlist.c101
-rw-r--r--tools/perf/util/intlist.h75
-rw-r--r--tools/perf/util/map.c41
-rw-r--r--tools/perf/util/map.h1
-rw-r--r--tools/perf/util/parse-events-test.c12
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/python.c6
-rw-r--r--tools/perf/util/rblist.c107
-rw-r--r--tools/perf/util/rblist.h47
-rw-r--r--tools/perf/util/session.c51
-rw-r--r--tools/perf/util/session.h24
-rw-r--r--tools/perf/util/strlist.c130
-rw-r--r--tools/perf/util/strlist.h11
-rw-r--r--tools/perf/util/symbol.c457
-rw-r--r--tools/perf/util/symbol.h54
-rw-r--r--tools/perf/util/target.c11
-rw-r--r--tools/power/x86/turbostat/Makefile1
-rw-r--r--tools/power/x86/turbostat/turbostat.877
-rw-r--r--tools/power/x86/turbostat/turbostat.c1333
-rw-r--r--tools/testing/fault-injection/failcmd.sh219
-rwxr-xr-xtools/testing/ktest/ktest.pl167
-rw-r--r--tools/testing/ktest/sample.conf52
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile6
-rw-r--r--tools/testing/selftests/cpu-hotplug/on-off-test.sh221
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile6
-rw-r--r--tools/testing/selftests/memory-hotplug/on-off-test.sh230
-rw-r--r--tools/usb/testusb.c21
-rw-r--r--tools/vm/slabinfo.c14
47 files changed, 2944 insertions, 855 deletions
diff --git a/tools/lib/traceevent/.gitignore b/tools/lib/traceevent/.gitignore
new file mode 100644
index 000000000000..35f56be5a4cd
--- /dev/null
+++ b/tools/lib/traceevent/.gitignore
@@ -0,0 +1 @@
TRACEEVENT-CFLAGS
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 46c2f6b7b123..14131cb0522d 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -207,7 +207,7 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
207libtraceevent.a: $(PEVENT_LIB_OBJS) 207libtraceevent.a: $(PEVENT_LIB_OBJS)
208 $(Q)$(do_build_static_lib) 208 $(Q)$(do_build_static_lib)
209 209
210$(PEVENT_LIB_OBJS): %.o: $(src)/%.c 210$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
211 $(Q)$(do_fpic_compile) 211 $(Q)$(do_fpic_compile)
212 212
213define make_version.h 213define make_version.h
@@ -272,6 +272,16 @@ ifneq ($(dep_includes),)
272 include $(dep_includes) 272 include $(dep_includes)
273endif 273endif
274 274
275### Detect environment changes
276TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
277
278TRACEEVENT-CFLAGS: force
279 @FLAGS='$(TRACK_CFLAGS)'; \
280 if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
281 echo 1>&2 " * new build flags or cross compiler"; \
282 echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
283 fi
284
275tags: force 285tags: force
276 $(RM) tags 286 $(RM) tags
277 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ 287 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
@@ -297,7 +307,7 @@ install: install_lib
297 307
298clean: 308clean:
299 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d 309 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
300 $(RM) tags TAGS 310 $(RM) TRACEEVENT-CFLAGS tags TAGS
301 311
302endif # skip-makefile 312endif # skip-makefile
303 313
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 75d74e5db8d5..35655c3a7b7a 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -319,6 +319,8 @@ LIB_H += $(ARCH_INCLUDE)
319LIB_H += util/cgroup.h 319LIB_H += util/cgroup.h
320LIB_H += $(TRACE_EVENT_DIR)event-parse.h 320LIB_H += $(TRACE_EVENT_DIR)event-parse.h
321LIB_H += util/target.h 321LIB_H += util/target.h
322LIB_H += util/rblist.h
323LIB_H += util/intlist.h
322 324
323LIB_OBJS += $(OUTPUT)util/abspath.o 325LIB_OBJS += $(OUTPUT)util/abspath.o
324LIB_OBJS += $(OUTPUT)util/alias.o 326LIB_OBJS += $(OUTPUT)util/alias.o
@@ -354,6 +356,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
354LIB_OBJS += $(OUTPUT)util/wrapper.o 356LIB_OBJS += $(OUTPUT)util/wrapper.o
355LIB_OBJS += $(OUTPUT)util/sigchain.o 357LIB_OBJS += $(OUTPUT)util/sigchain.o
356LIB_OBJS += $(OUTPUT)util/symbol.o 358LIB_OBJS += $(OUTPUT)util/symbol.o
359LIB_OBJS += $(OUTPUT)util/dso-test-data.o
357LIB_OBJS += $(OUTPUT)util/color.o 360LIB_OBJS += $(OUTPUT)util/color.o
358LIB_OBJS += $(OUTPUT)util/pager.o 361LIB_OBJS += $(OUTPUT)util/pager.o
359LIB_OBJS += $(OUTPUT)util/header.o 362LIB_OBJS += $(OUTPUT)util/header.o
@@ -382,6 +385,8 @@ LIB_OBJS += $(OUTPUT)util/xyarray.o
382LIB_OBJS += $(OUTPUT)util/cpumap.o 385LIB_OBJS += $(OUTPUT)util/cpumap.o
383LIB_OBJS += $(OUTPUT)util/cgroup.o 386LIB_OBJS += $(OUTPUT)util/cgroup.o
384LIB_OBJS += $(OUTPUT)util/target.o 387LIB_OBJS += $(OUTPUT)util/target.o
388LIB_OBJS += $(OUTPUT)util/rblist.o
389LIB_OBJS += $(OUTPUT)util/intlist.o
385 390
386BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 391BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
387 392
@@ -803,6 +808,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
803$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 808$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
804 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 809 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
805 810
811$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
812 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
813
806$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS 814$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
807 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 815 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
808 816
@@ -979,7 +987,8 @@ clean:
979 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 987 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
980 $(MAKE) -C Documentation/ clean 988 $(MAKE) -C Documentation/ clean
981 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 989 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
982 $(RM) $(OUTPUT)util/*-{bison,flex}* 990 $(RM) $(OUTPUT)util/*-bison*
991 $(RM) $(OUTPUT)util/*-flex*
983 $(python-clean) 992 $(python-clean)
984 993
985.PHONY: all install clean strip $(LIBTRACEEVENT) 994.PHONY: all install clean strip $(LIBTRACEEVENT)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f5a6452931e6..4db6e1ba54e3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -313,7 +313,7 @@ try_again:
313 } 313 }
314 } 314 }
315 315
316 perf_session__update_sample_type(session); 316 perf_session__set_id_hdr_size(session);
317} 317}
318 318
319static int process_buildids(struct perf_record *rec) 319static int process_buildids(struct perf_record *rec)
@@ -844,8 +844,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
844 struct perf_record *rec = &record; 844 struct perf_record *rec = &record;
845 char errbuf[BUFSIZ]; 845 char errbuf[BUFSIZ];
846 846
847 perf_header__set_cmdline(argc, argv);
848
849 evsel_list = perf_evlist__new(NULL, NULL); 847 evsel_list = perf_evlist__new(NULL, NULL);
850 if (evsel_list == NULL) 848 if (evsel_list == NULL)
851 return -ENOMEM; 849 return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 69b1c1185159..7c88a243b5db 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -249,8 +249,9 @@ static int process_read_event(struct perf_tool *tool,
249static int perf_report__setup_sample_type(struct perf_report *rep) 249static int perf_report__setup_sample_type(struct perf_report *rep)
250{ 250{
251 struct perf_session *self = rep->session; 251 struct perf_session *self = rep->session;
252 u64 sample_type = perf_evlist__sample_type(self->evlist);
252 253
253 if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 254 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
254 if (sort__has_parent) { 255 if (sort__has_parent) {
255 ui__error("Selected --sort parent, but no " 256 ui__error("Selected --sort parent, but no "
256 "callchain data. Did you call " 257 "callchain data. Did you call "
@@ -274,7 +275,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
274 275
275 if (sort__branch_mode == 1) { 276 if (sort__branch_mode == 1) {
276 if (!self->fd_pipe && 277 if (!self->fd_pipe &&
277 !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { 278 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
278 ui__error("Selected -b but no branch data. " 279 ui__error("Selected -b but no branch data. "
279 "Did you call perf record without -b?\n"); 280 "Did you call perf record without -b?\n");
280 return -1; 281 return -1;
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 5ce30305462b..1d592f5cbea9 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -478,7 +478,6 @@ static int test__basic_mmap(void)
478 unsigned int nr_events[nsyscalls], 478 unsigned int nr_events[nsyscalls],
479 expected_nr_events[nsyscalls], i, j; 479 expected_nr_events[nsyscalls], i, j;
480 struct perf_evsel *evsels[nsyscalls], *evsel; 480 struct perf_evsel *evsels[nsyscalls], *evsel;
481 int sample_size = __perf_evsel__sample_size(attr.sample_type);
482 481
483 for (i = 0; i < nsyscalls; ++i) { 482 for (i = 0; i < nsyscalls; ++i) {
484 char name[64]; 483 char name[64];
@@ -563,8 +562,7 @@ static int test__basic_mmap(void)
563 goto out_munmap; 562 goto out_munmap;
564 } 563 }
565 564
566 err = perf_event__parse_sample(event, attr.sample_type, sample_size, 565 err = perf_evlist__parse_sample(evlist, event, &sample, false);
567 false, &sample, false);
568 if (err) { 566 if (err) {
569 pr_err("Can't parse sample, err = %d\n", err); 567 pr_err("Can't parse sample, err = %d\n", err);
570 goto out_munmap; 568 goto out_munmap;
@@ -661,12 +659,12 @@ static int test__PERF_RECORD(void)
661 const char *cmd = "sleep"; 659 const char *cmd = "sleep";
662 const char *argv[] = { cmd, "1", NULL, }; 660 const char *argv[] = { cmd, "1", NULL, };
663 char *bname; 661 char *bname;
664 u64 sample_type, prev_time = 0; 662 u64 prev_time = 0;
665 bool found_cmd_mmap = false, 663 bool found_cmd_mmap = false,
666 found_libc_mmap = false, 664 found_libc_mmap = false,
667 found_vdso_mmap = false, 665 found_vdso_mmap = false,
668 found_ld_mmap = false; 666 found_ld_mmap = false;
669 int err = -1, errs = 0, i, wakeups = 0, sample_size; 667 int err = -1, errs = 0, i, wakeups = 0;
670 u32 cpu; 668 u32 cpu;
671 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 669 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
672 670
@@ -757,13 +755,6 @@ static int test__PERF_RECORD(void)
757 } 755 }
758 756
759 /* 757 /*
760 * We'll need these two to parse the PERF_SAMPLE_* fields in each
761 * event.
762 */
763 sample_type = perf_evlist__sample_type(evlist);
764 sample_size = __perf_evsel__sample_size(sample_type);
765
766 /*
767 * Now that all is properly set up, enable the events, they will 758 * Now that all is properly set up, enable the events, they will
768 * count just on workload.pid, which will start... 759 * count just on workload.pid, which will start...
769 */ 760 */
@@ -788,9 +779,7 @@ static int test__PERF_RECORD(void)
788 if (type < PERF_RECORD_MAX) 779 if (type < PERF_RECORD_MAX)
789 nr_events[type]++; 780 nr_events[type]++;
790 781
791 err = perf_event__parse_sample(event, sample_type, 782 err = perf_evlist__parse_sample(evlist, event, &sample, false);
792 sample_size, true,
793 &sample, false);
794 if (err < 0) { 783 if (err < 0) {
795 if (verbose) 784 if (verbose)
796 perf_event__fprintf(event, stderr); 785 perf_event__fprintf(event, stderr);
@@ -1142,6 +1131,10 @@ static struct test {
1142 .func = test__perf_pmu, 1131 .func = test__perf_pmu,
1143 }, 1132 },
1144 { 1133 {
1134 .desc = "Test dso data interface",
1135 .func = dso__test_data,
1136 },
1137 {
1145 .func = NULL, 1138 .func = NULL,
1146 }, 1139 },
1147}; 1140};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e3cab5f088f8..68cd61ef6ac5 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -38,6 +38,7 @@
38#include "util/cpumap.h" 38#include "util/cpumap.h"
39#include "util/xyarray.h" 39#include "util/xyarray.h"
40#include "util/sort.h" 40#include "util/sort.h"
41#include "util/intlist.h"
41 42
42#include "util/debug.h" 43#include "util/debug.h"
43 44
@@ -125,7 +126,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
125 /* 126 /*
126 * We can't annotate with just /proc/kallsyms 127 * We can't annotate with just /proc/kallsyms
127 */ 128 */
128 if (map->dso->symtab_type == SYMTAB__KALLSYMS) { 129 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
129 pr_err("Can't annotate %s: No vmlinux file was found in the " 130 pr_err("Can't annotate %s: No vmlinux file was found in the "
130 "path\n", sym->name); 131 "path\n", sym->name);
131 sleep(1); 132 sleep(1);
@@ -706,8 +707,16 @@ static void perf_event__process_sample(struct perf_tool *tool,
706 int err; 707 int err;
707 708
708 if (!machine && perf_guest) { 709 if (!machine && perf_guest) {
709 pr_err("Can't find guest [%d]'s kernel information\n", 710 static struct intlist *seen;
710 event->ip.pid); 711
712 if (!seen)
713 seen = intlist__new();
714
715 if (!intlist__has_entry(seen, event->ip.pid)) {
716 pr_err("Can't find guest [%d]'s kernel information\n",
717 event->ip.pid);
718 intlist__add(seen, event->ip.pid);
719 }
711 return; 720 return;
712 } 721 }
713 722
@@ -811,7 +820,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
811 int ret; 820 int ret;
812 821
813 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { 822 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
814 ret = perf_session__parse_sample(session, event, &sample); 823 ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
815 if (ret) { 824 if (ret) {
816 pr_err("Can't parse sample, err = %d\n", ret); 825 pr_err("Can't parse sample, err = %d\n", ret);
817 continue; 826 continue;
@@ -943,8 +952,10 @@ try_again:
943 * based cpu-clock-tick sw counter, which 952 * based cpu-clock-tick sw counter, which
944 * is always available even if no PMU support: 953 * is always available even if no PMU support:
945 */ 954 */
946 if (attr->type == PERF_TYPE_HARDWARE && 955 if ((err == ENOENT || err == ENXIO) &&
947 attr->config == PERF_COUNT_HW_CPU_CYCLES) { 956 (attr->type == PERF_TYPE_HARDWARE) &&
957 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
958
948 if (verbose) 959 if (verbose)
949 ui__warning("Cycles event not supported,\n" 960 ui__warning("Cycles event not supported,\n"
950 "trying to fall back to cpu-clock-ticks\n"); 961 "trying to fall back to cpu-clock-ticks\n");
@@ -1032,7 +1043,7 @@ static int __cmd_top(struct perf_top *top)
1032 &top->session->host_machine); 1043 &top->session->host_machine);
1033 perf_top__start_counters(top); 1044 perf_top__start_counters(top);
1034 top->session->evlist = top->evlist; 1045 top->session->evlist = top->evlist;
1035 perf_session__update_sample_type(top->session); 1046 perf_session__set_id_hdr_size(top->session);
1036 1047
1037 /* Wait for a minimal set of events before starting the snapshot */ 1048 /* Wait for a minimal set of events before starting the snapshot */
1038 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 1049 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 482f0517b61e..413bd62eedb1 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -978,8 +978,8 @@ static int hist_browser__dump(struct hist_browser *browser)
978 fp = fopen(filename, "w"); 978 fp = fopen(filename, "w");
979 if (fp == NULL) { 979 if (fp == NULL) {
980 char bf[64]; 980 char bf[64];
981 strerror_r(errno, bf, sizeof(bf)); 981 const char *err = strerror_r(errno, bf, sizeof(bf));
982 ui_helpline__fpush("Couldn't write to %s: %s", filename, bf); 982 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
983 return -1; 983 return -1;
984 } 984 }
985 985
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 8069dfb5ba77..3a282c0057d2 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -426,7 +426,18 @@ int symbol__alloc_hist(struct symbol *sym)
426{ 426{
427 struct annotation *notes = symbol__annotation(sym); 427 struct annotation *notes = symbol__annotation(sym);
428 const size_t size = symbol__size(sym); 428 const size_t size = symbol__size(sym);
429 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 429 size_t sizeof_sym_hist;
430
431 /* Check for overflow when calculating sizeof_sym_hist */
432 if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
433 return -1;
434
435 sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
436
437 /* Check for overflow in zalloc argument */
438 if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
439 / symbol_conf.nr_events)
440 return -1;
430 441
431 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 442 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
432 if (notes->src == NULL) 443 if (notes->src == NULL)
@@ -777,7 +788,7 @@ fallback:
777 free_filename = false; 788 free_filename = false;
778 } 789 }
779 790
780 if (dso->symtab_type == SYMTAB__KALLSYMS) { 791 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
781 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 792 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
782 char *build_id_msg = NULL; 793 char *build_id_msg = NULL;
783 794
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c
new file mode 100644
index 000000000000..541cdc72c7df
--- /dev/null
+++ b/tools/perf/util/dso-test-data.c
@@ -0,0 +1,153 @@
1#include "util.h"
2
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <string.h>
8
9#include "symbol.h"
10
11#define TEST_ASSERT_VAL(text, cond) \
12do { \
13 if (!(cond)) { \
14 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
15 return -1; \
16 } \
17} while (0)
18
19static char *test_file(int size)
20{
21 static char buf_templ[] = "/tmp/test-XXXXXX";
22 char *templ = buf_templ;
23 int fd, i;
24 unsigned char *buf;
25
26 fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC);
27
28 buf = malloc(size);
29 if (!buf) {
30 close(fd);
31 return NULL;
32 }
33
34 for (i = 0; i < size; i++)
35 buf[i] = (unsigned char) ((int) i % 10);
36
37 if (size != write(fd, buf, size))
38 templ = NULL;
39
40 close(fd);
41 return templ;
42}
43
44#define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
45
46struct test_data_offset {
47 off_t offset;
48 u8 data[10];
49 int size;
50};
51
52struct test_data_offset offsets[] = {
53 /* Fill first cache page. */
54 {
55 .offset = 10,
56 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
57 .size = 10,
58 },
59 /* Read first cache page. */
60 {
61 .offset = 10,
62 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
63 .size = 10,
64 },
65 /* Fill cache boundary pages. */
66 {
67 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
68 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
69 .size = 10,
70 },
71 /* Read cache boundary pages. */
72 {
73 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
74 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
75 .size = 10,
76 },
77 /* Fill final cache page. */
78 {
79 .offset = TEST_FILE_SIZE - 10,
80 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
81 .size = 10,
82 },
83 /* Read final cache page. */
84 {
85 .offset = TEST_FILE_SIZE - 10,
86 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
87 .size = 10,
88 },
89 /* Read final cache page. */
90 {
91 .offset = TEST_FILE_SIZE - 3,
92 .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
93 .size = 3,
94 },
95};
96
97int dso__test_data(void)
98{
99 struct machine machine;
100 struct dso *dso;
101 char *file = test_file(TEST_FILE_SIZE);
102 size_t i;
103
104 TEST_ASSERT_VAL("No test file", file);
105
106 memset(&machine, 0, sizeof(machine));
107
108 dso = dso__new((const char *)file);
109
110 /* Basic 10 bytes tests. */
111 for (i = 0; i < ARRAY_SIZE(offsets); i++) {
112 struct test_data_offset *data = &offsets[i];
113 ssize_t size;
114 u8 buf[10];
115
116 memset(buf, 0, 10);
117 size = dso__data_read_offset(dso, &machine, data->offset,
118 buf, 10);
119
120 TEST_ASSERT_VAL("Wrong size", size == data->size);
121 TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
122 }
123
124 /* Read cross multiple cache pages. */
125 {
126 ssize_t size;
127 int c;
128 u8 *buf;
129
130 buf = malloc(TEST_FILE_SIZE);
131 TEST_ASSERT_VAL("ENOMEM\n", buf);
132
133 /* First iteration to fill caches, second one to read them. */
134 for (c = 0; c < 2; c++) {
135 memset(buf, 0, TEST_FILE_SIZE);
136 size = dso__data_read_offset(dso, &machine, 10,
137 buf, TEST_FILE_SIZE);
138
139 TEST_ASSERT_VAL("Wrong size",
140 size == (TEST_FILE_SIZE - 10));
141
142 for (i = 0; i < (size_t)size; i++)
143 TEST_ASSERT_VAL("Wrong data",
144 buf[i] == (i % 10));
145 }
146
147 free(buf);
148 }
149
150 dso__delete(dso);
151 unlink(file);
152 return 0;
153}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1b197280c621..d84870b06426 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -197,9 +197,6 @@ int perf_event__preprocess_sample(const union perf_event *self,
197 197
198const char *perf_event__name(unsigned int id); 198const char *perf_event__name(unsigned int id);
199 199
200int perf_event__parse_sample(const union perf_event *event, u64 type,
201 int sample_size, bool sample_id_all,
202 struct perf_sample *sample, bool swapped);
203int perf_event__synthesize_sample(union perf_event *event, u64 type, 200int perf_event__synthesize_sample(union perf_event *event, u64 type,
204 const struct perf_sample *sample, 201 const struct perf_sample *sample,
205 bool swapped); 202 bool swapped);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f74e9560350e..9b38681add9e 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -214,7 +214,7 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
214 attrs[i].type = PERF_TYPE_TRACEPOINT; 214 attrs[i].type = PERF_TYPE_TRACEPOINT;
215 attrs[i].config = err; 215 attrs[i].config = err;
216 attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | 216 attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
217 PERF_SAMPLE_CPU); 217 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD);
218 attrs[i].sample_period = 1; 218 attrs[i].sample_period = 1;
219 } 219 }
220 220
@@ -881,3 +881,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
881 881
882 return 0; 882 return 0;
883} 883}
884
885int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
886 struct perf_sample *sample, bool swapped)
887{
888 struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node);
889 return perf_evsel__parse_sample(e, event, sample, swapped);
890}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 40d4d3cdced0..528c1acd9298 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -122,6 +122,9 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
122bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); 122bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
123u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); 123u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
124 124
125int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
126 struct perf_sample *sample, bool swapped);
127
125bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); 128bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
126bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); 129bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
127 130
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e81771364867..2eaae140def2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -20,7 +20,7 @@
20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) 21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
22 22
23int __perf_evsel__sample_size(u64 sample_type) 23static int __perf_evsel__sample_size(u64 sample_type)
24{ 24{
25 u64 mask = sample_type & PERF_SAMPLE_MASK; 25 u64 mask = sample_type & PERF_SAMPLE_MASK;
26 int size = 0; 26 int size = 0;
@@ -53,6 +53,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
53 evsel->attr = *attr; 53 evsel->attr = *attr;
54 INIT_LIST_HEAD(&evsel->node); 54 INIT_LIST_HEAD(&evsel->node);
55 hists__init(&evsel->hists); 55 hists__init(&evsel->hists);
56 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
56} 57}
57 58
58struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 59struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -728,10 +729,10 @@ static bool sample_overlap(const union perf_event *event,
728 return false; 729 return false;
729} 730}
730 731
731int perf_event__parse_sample(const union perf_event *event, u64 type, 732int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
732 int sample_size, bool sample_id_all,
733 struct perf_sample *data, bool swapped) 733 struct perf_sample *data, bool swapped)
734{ 734{
735 u64 type = evsel->attr.sample_type;
735 const u64 *array; 736 const u64 *array;
736 737
737 /* 738 /*
@@ -746,14 +747,14 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
746 data->period = 1; 747 data->period = 1;
747 748
748 if (event->header.type != PERF_RECORD_SAMPLE) { 749 if (event->header.type != PERF_RECORD_SAMPLE) {
749 if (!sample_id_all) 750 if (!evsel->attr.sample_id_all)
750 return 0; 751 return 0;
751 return perf_event__parse_id_sample(event, type, data, swapped); 752 return perf_event__parse_id_sample(event, type, data, swapped);
752 } 753 }
753 754
754 array = event->sample.array; 755 array = event->sample.array;
755 756
756 if (sample_size + sizeof(event->header) > event->header.size) 757 if (evsel->sample_size + sizeof(event->header) > event->header.size)
757 return -EFAULT; 758 return -EFAULT;
758 759
759 if (type & PERF_SAMPLE_IP) { 760 if (type & PERF_SAMPLE_IP) {
@@ -895,7 +896,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
895 u.val32[1] = sample->tid; 896 u.val32[1] = sample->tid;
896 if (swapped) { 897 if (swapped) {
897 /* 898 /*
898 * Inverse of what is done in perf_event__parse_sample 899 * Inverse of what is done in perf_evsel__parse_sample
899 */ 900 */
900 u.val32[0] = bswap_32(u.val32[0]); 901 u.val32[0] = bswap_32(u.val32[0]);
901 u.val32[1] = bswap_32(u.val32[1]); 902 u.val32[1] = bswap_32(u.val32[1]);
@@ -930,7 +931,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
930 u.val32[0] = sample->cpu; 931 u.val32[0] = sample->cpu;
931 if (swapped) { 932 if (swapped) {
932 /* 933 /*
933 * Inverse of what is done in perf_event__parse_sample 934 * Inverse of what is done in perf_evsel__parse_sample
934 */ 935 */
935 u.val32[0] = bswap_32(u.val32[0]); 936 u.val32[0] = bswap_32(u.val32[0]);
936 u.val64 = bswap_64(u.val64); 937 u.val64 = bswap_64(u.val64);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 67cc5033d192..b559929983bb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -65,6 +65,7 @@ struct perf_evsel {
65 void *func; 65 void *func;
66 void *data; 66 void *data;
67 } handler; 67 } handler;
68 unsigned int sample_size;
68 bool supported; 69 bool supported;
69}; 70};
70 71
@@ -177,13 +178,8 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
177 return __perf_evsel__read(evsel, ncpus, nthreads, true); 178 return __perf_evsel__read(evsel, ncpus, nthreads, true);
178} 179}
179 180
180int __perf_evsel__sample_size(u64 sample_type);
181
182static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
183{
184 return __perf_evsel__sample_size(evsel->attr.sample_type);
185}
186
187void hists__init(struct hists *hists); 181void hists__init(struct hists *hists);
188 182
183int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
184 struct perf_sample *sample, bool swapped);
189#endif /* __PERF_EVSEL_H */ 185#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 5a47aba46759..74ea3c2f8138 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -174,6 +174,15 @@ perf_header__set_cmdline(int argc, const char **argv)
174{ 174{
175 int i; 175 int i;
176 176
177 /*
178 * If header_argv has already been set, do not override it.
179 * This allows a command to set the cmdline, parse args and
180 * then call another builtin function that implements a
181 * command -- e.g, cmd_kvm calling cmd_record.
182 */
183 if (header_argv)
184 return 0;
185
177 header_argc = (u32)argc; 186 header_argc = (u32)argc;
178 187
179 /* do not include NULL termination */ 188 /* do not include NULL termination */
@@ -1212,6 +1221,12 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1212 attr.exclude_user, 1221 attr.exclude_user,
1213 attr.exclude_kernel); 1222 attr.exclude_kernel);
1214 1223
1224 fprintf(fp, ", excl_host = %d, excl_guest = %d",
1225 attr.exclude_host,
1226 attr.exclude_guest);
1227
1228 fprintf(fp, ", precise_ip = %d", attr.precise_ip);
1229
1215 if (nr) 1230 if (nr)
1216 fprintf(fp, ", id = {"); 1231 fprintf(fp, ", id = {");
1217 1232
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 514e2a4b367d..f247ef2789a4 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -708,7 +708,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
708 bool printed = false; 708 bool printed = false;
709 struct rb_node *node; 709 struct rb_node *node;
710 int i = 0; 710 int i = 0;
711 int ret; 711 int ret = 0;
712 712
713 /* 713 /*
714 * If have one single callchain root, don't bother printing 714 * If have one single callchain root, don't bother printing
@@ -747,8 +747,11 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
747 root = &cnode->rb_root; 747 root = &cnode->rb_root;
748 } 748 }
749 749
750 return __callchain__fprintf_graph(fp, root, total_samples, 750 ret += __callchain__fprintf_graph(fp, root, total_samples,
751 1, 1, left_margin); 751 1, 1, left_margin);
752 ret += fprintf(fp, "\n");
753
754 return ret;
752} 755}
753 756
754static size_t __callchain__fprintf_flat(FILE *fp, 757static size_t __callchain__fprintf_flat(FILE *fp,
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
new file mode 100644
index 000000000000..fd530dced9cb
--- /dev/null
+++ b/tools/perf/util/intlist.c
@@ -0,0 +1,101 @@
1/*
2 * Based on intlist.c by:
3 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
4 *
5 * Licensed under the GPLv2.
6 */
7
8#include <errno.h>
9#include <stdlib.h>
10#include <linux/compiler.h>
11
12#include "intlist.h"
13
14static struct rb_node *intlist__node_new(struct rblist *rblist __used,
15 const void *entry)
16{
17 int i = (int)((long)entry);
18 struct rb_node *rc = NULL;
19 struct int_node *node = malloc(sizeof(*node));
20
21 if (node != NULL) {
22 node->i = i;
23 rc = &node->rb_node;
24 }
25
26 return rc;
27}
28
29static void int_node__delete(struct int_node *ilist)
30{
31 free(ilist);
32}
33
34static void intlist__node_delete(struct rblist *rblist __used,
35 struct rb_node *rb_node)
36{
37 struct int_node *node = container_of(rb_node, struct int_node, rb_node);
38
39 int_node__delete(node);
40}
41
42static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
43{
44 int i = (int)((long)entry);
45 struct int_node *node = container_of(rb_node, struct int_node, rb_node);
46
47 return node->i - i;
48}
49
50int intlist__add(struct intlist *ilist, int i)
51{
52 return rblist__add_node(&ilist->rblist, (void *)((long)i));
53}
54
55void intlist__remove(struct intlist *ilist __used, struct int_node *node)
56{
57 int_node__delete(node);
58}
59
60struct int_node *intlist__find(struct intlist *ilist, int i)
61{
62 struct int_node *node = NULL;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
64
65 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node);
67
68 return node;
69}
70
71struct intlist *intlist__new(void)
72{
73 struct intlist *ilist = malloc(sizeof(*ilist));
74
75 if (ilist != NULL) {
76 rblist__init(&ilist->rblist);
77 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete;
80 }
81
82 return ilist;
83}
84
85void intlist__delete(struct intlist *ilist)
86{
87 if (ilist != NULL)
88 rblist__delete(&ilist->rblist);
89}
90
91struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
92{
93 struct int_node *node = NULL;
94 struct rb_node *rb_node;
95
96 rb_node = rblist__entry(&ilist->rblist, idx);
97 if (rb_node)
98 node = container_of(rb_node, struct int_node, rb_node);
99
100 return node;
101}
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
new file mode 100644
index 000000000000..6d63ab90db50
--- /dev/null
+++ b/tools/perf/util/intlist.h
@@ -0,0 +1,75 @@
1#ifndef __PERF_INTLIST_H
2#define __PERF_INTLIST_H
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7#include "rblist.h"
8
9struct int_node {
10 struct rb_node rb_node;
11 int i;
12};
13
14struct intlist {
15 struct rblist rblist;
16};
17
18struct intlist *intlist__new(void);
19void intlist__delete(struct intlist *ilist);
20
21void intlist__remove(struct intlist *ilist, struct int_node *in);
22int intlist__add(struct intlist *ilist, int i);
23
24struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
25struct int_node *intlist__find(struct intlist *ilist, int i);
26
27static inline bool intlist__has_entry(struct intlist *ilist, int i)
28{
29 return intlist__find(ilist, i) != NULL;
30}
31
32static inline bool intlist__empty(const struct intlist *ilist)
33{
34 return rblist__empty(&ilist->rblist);
35}
36
37static inline unsigned int intlist__nr_entries(const struct intlist *ilist)
38{
39 return rblist__nr_entries(&ilist->rblist);
40}
41
42/* For intlist iteration */
43static inline struct int_node *intlist__first(struct intlist *ilist)
44{
45 struct rb_node *rn = rb_first(&ilist->rblist.entries);
46 return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
47}
48static inline struct int_node *intlist__next(struct int_node *in)
49{
50 struct rb_node *rn;
51 if (!in)
52 return NULL;
53 rn = rb_next(&in->rb_node);
54 return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
55}
56
57/**
58 * intlist_for_each - iterate over a intlist
59 * @pos: the &struct int_node to use as a loop cursor.
60 * @ilist: the &struct intlist for loop.
61 */
62#define intlist__for_each(pos, ilist) \
63 for (pos = intlist__first(ilist); pos; pos = intlist__next(pos))
64
65/**
66 * intlist_for_each_safe - iterate over a intlist safe against removal of
67 * int_node
68 * @pos: the &struct int_node to use as a loop cursor.
69 * @n: another &struct int_node to use as temporary storage.
70 * @ilist: the &struct intlist for loop.
71 */
72#define intlist__for_each_safe(pos, n, ilist) \
73 for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\
74 pos = n, n = intlist__next(n))
75#endif /* __PERF_INTLIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index a1f4e3669142..cc33486ad9e2 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -7,6 +7,8 @@
7#include <stdio.h> 7#include <stdio.h>
8#include <unistd.h> 8#include <unistd.h>
9#include "map.h" 9#include "map.h"
10#include "thread.h"
11#include "strlist.h"
10 12
11const char *map_type__name[MAP__NR_TYPES] = { 13const char *map_type__name[MAP__NR_TYPES] = {
12 [MAP__FUNCTION] = "Functions", 14 [MAP__FUNCTION] = "Functions",
@@ -585,7 +587,21 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
585 self->kmaps.machine = self; 587 self->kmaps.machine = self;
586 self->pid = pid; 588 self->pid = pid;
587 self->root_dir = strdup(root_dir); 589 self->root_dir = strdup(root_dir);
588 return self->root_dir == NULL ? -ENOMEM : 0; 590 if (self->root_dir == NULL)
591 return -ENOMEM;
592
593 if (pid != HOST_KERNEL_ID) {
594 struct thread *thread = machine__findnew_thread(self, pid);
595 char comm[64];
596
597 if (thread == NULL)
598 return -ENOMEM;
599
600 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
601 thread__set_comm(thread, comm);
602 }
603
604 return 0;
589} 605}
590 606
591static void dsos__delete(struct list_head *self) 607static void dsos__delete(struct list_head *self)
@@ -680,7 +696,15 @@ struct machine *machines__findnew(struct rb_root *self, pid_t pid)
680 (symbol_conf.guestmount)) { 696 (symbol_conf.guestmount)) {
681 sprintf(path, "%s/%d", symbol_conf.guestmount, pid); 697 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
682 if (access(path, R_OK)) { 698 if (access(path, R_OK)) {
683 pr_err("Can't access file %s\n", path); 699 static struct strlist *seen;
700
701 if (!seen)
702 seen = strlist__new(true, NULL);
703
704 if (!strlist__has_entry(seen, path)) {
705 pr_err("Can't access file %s\n", path);
706 strlist__add(seen, path);
707 }
684 machine = NULL; 708 machine = NULL;
685 goto out; 709 goto out;
686 } 710 }
@@ -714,3 +738,16 @@ char *machine__mmap_name(struct machine *self, char *bf, size_t size)
714 738
715 return bf; 739 return bf;
716} 740}
741
742void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
743{
744 struct rb_node *node;
745 struct machine *machine;
746
747 for (node = rb_first(machines); node; node = rb_next(node)) {
748 machine = rb_entry(node, struct machine, rb_node);
749 machine->id_hdr_size = id_hdr_size;
750 }
751
752 return;
753}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index c14c665d9a25..03a1e9b08b21 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -151,6 +151,7 @@ struct machine *machines__add(struct rb_root *self, pid_t pid,
151struct machine *machines__find_host(struct rb_root *self); 151struct machine *machines__find_host(struct rb_root *self);
152struct machine *machines__find(struct rb_root *self, pid_t pid); 152struct machine *machines__find(struct rb_root *self, pid_t pid);
153struct machine *machines__findnew(struct rb_root *self, pid_t pid); 153struct machine *machines__findnew(struct rb_root *self, pid_t pid);
154void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
154char *machine__mmap_name(struct machine *self, char *bf, size_t size); 155char *machine__mmap_name(struct machine *self, char *bf, size_t size);
155int machine__init(struct machine *self, const char *root_dir, pid_t pid); 156int machine__init(struct machine *self, const char *root_dir, pid_t pid);
156void machine__exit(struct machine *self); 157void machine__exit(struct machine *self);
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 1b997d2b89ce..127d648cc548 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -13,6 +13,9 @@ do { \
13 } \ 13 } \
14} while (0) 14} while (0)
15 15
16#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
17 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
18
16static int test__checkevent_tracepoint(struct perf_evlist *evlist) 19static int test__checkevent_tracepoint(struct perf_evlist *evlist)
17{ 20{
18 struct perf_evsel *evsel = list_entry(evlist->entries.next, 21 struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -21,8 +24,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
21 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 24 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
22 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 25 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
23 TEST_ASSERT_VAL("wrong sample_type", 26 TEST_ASSERT_VAL("wrong sample_type",
24 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == 27 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
25 evsel->attr.sample_type);
26 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); 28 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
27 return 0; 29 return 0;
28} 30}
@@ -37,8 +39,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
37 TEST_ASSERT_VAL("wrong type", 39 TEST_ASSERT_VAL("wrong type",
38 PERF_TYPE_TRACEPOINT == evsel->attr.type); 40 PERF_TYPE_TRACEPOINT == evsel->attr.type);
39 TEST_ASSERT_VAL("wrong sample_type", 41 TEST_ASSERT_VAL("wrong sample_type",
40 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) 42 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
41 == evsel->attr.sample_type);
42 TEST_ASSERT_VAL("wrong sample_period", 43 TEST_ASSERT_VAL("wrong sample_period",
43 1 == evsel->attr.sample_period); 44 1 == evsel->attr.sample_period);
44 } 45 }
@@ -428,8 +429,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
428 evsel = list_entry(evsel->node.next, struct perf_evsel, node); 429 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
429 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 430 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
430 TEST_ASSERT_VAL("wrong sample_type", 431 TEST_ASSERT_VAL("wrong sample_type",
431 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) == 432 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
432 evsel->attr.sample_type);
433 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); 433 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
434 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); 434 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
435 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); 435 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1aa721d7c10f..74a5af4d33ec 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -377,6 +377,7 @@ static int add_tracepoint(struct list_head **list, int *idx,
377 attr.sample_type |= PERF_SAMPLE_RAW; 377 attr.sample_type |= PERF_SAMPLE_RAW;
378 attr.sample_type |= PERF_SAMPLE_TIME; 378 attr.sample_type |= PERF_SAMPLE_TIME;
379 attr.sample_type |= PERF_SAMPLE_CPU; 379 attr.sample_type |= PERF_SAMPLE_CPU;
380 attr.sample_type |= PERF_SAMPLE_PERIOD;
380 attr.sample_period = 1; 381 attr.sample_period = 1;
381 382
382 snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); 383 snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
@@ -489,6 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
489 attr.bp_len = HW_BREAKPOINT_LEN_4; 490 attr.bp_len = HW_BREAKPOINT_LEN_4;
490 491
491 attr.type = PERF_TYPE_BREAKPOINT; 492 attr.type = PERF_TYPE_BREAKPOINT;
493 attr.sample_period = 1;
492 494
493 return add_event(list, idx, &attr, NULL); 495 return add_event(list, idx, &attr, NULL);
494} 496}
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 99d02aa57dbf..594f8fad5ecd 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -1,6 +1,7 @@
1#include "util.h" 1#include "util.h"
2#include "parse-options.h" 2#include "parse-options.h"
3#include "cache.h" 3#include "cache.h"
4#include "header.h"
4 5
5#define OPT_SHORT 1 6#define OPT_SHORT 1
6#define OPT_UNSET 2 7#define OPT_UNSET 2
@@ -413,6 +414,8 @@ int parse_options(int argc, const char **argv, const struct option *options,
413{ 414{
414 struct parse_opt_ctx_t ctx; 415 struct parse_opt_ctx_t ctx;
415 416
417 perf_header__set_cmdline(argc, argv);
418
416 parse_options_start(&ctx, argc, argv, flags); 419 parse_options_start(&ctx, argc, argv, flags);
417 switch (parse_options_step(&ctx, options, usagestr)) { 420 switch (parse_options_step(&ctx, options, usagestr)) {
418 case PARSE_OPT_HELP: 421 case PARSE_OPT_HELP:
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index e03b58a48424..0688bfb6d280 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -797,17 +797,13 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
797 797
798 event = perf_evlist__mmap_read(evlist, cpu); 798 event = perf_evlist__mmap_read(evlist, cpu);
799 if (event != NULL) { 799 if (event != NULL) {
800 struct perf_evsel *first;
801 PyObject *pyevent = pyrf_event__new(event); 800 PyObject *pyevent = pyrf_event__new(event);
802 struct pyrf_event *pevent = (struct pyrf_event *)pyevent; 801 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
803 802
804 if (pyevent == NULL) 803 if (pyevent == NULL)
805 return PyErr_NoMemory(); 804 return PyErr_NoMemory();
806 805
807 first = list_entry(evlist->entries.next, struct perf_evsel, node); 806 err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
808 err = perf_event__parse_sample(event, first->attr.sample_type,
809 perf_evsel__sample_size(first),
810 sample_id_all, &pevent->sample, false);
811 if (err) 807 if (err)
812 return PyErr_Format(PyExc_OSError, 808 return PyErr_Format(PyExc_OSError,
813 "perf: can't parse sample, err=%d", err); 809 "perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
new file mode 100644
index 000000000000..0171fb611004
--- /dev/null
+++ b/tools/perf/util/rblist.c
@@ -0,0 +1,107 @@
1/*
2 * Based on strlist.c by:
3 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
4 *
5 * Licensed under the GPLv2.
6 */
7
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "rblist.h"
13
14int rblist__add_node(struct rblist *rblist, const void *new_entry)
15{
16 struct rb_node **p = &rblist->entries.rb_node;
17 struct rb_node *parent = NULL, *new_node;
18
19 while (*p != NULL) {
20 int rc;
21
22 parent = *p;
23
24 rc = rblist->node_cmp(parent, new_entry);
25 if (rc > 0)
26 p = &(*p)->rb_left;
27 else if (rc < 0)
28 p = &(*p)->rb_right;
29 else
30 return -EEXIST;
31 }
32
33 new_node = rblist->node_new(rblist, new_entry);
34 if (new_node == NULL)
35 return -ENOMEM;
36
37 rb_link_node(new_node, parent, p);
38 rb_insert_color(new_node, &rblist->entries);
39 ++rblist->nr_entries;
40
41 return 0;
42}
43
44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
45{
46 rb_erase(rb_node, &rblist->entries);
47 rblist->node_delete(rblist, rb_node);
48}
49
50struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
51{
52 struct rb_node **p = &rblist->entries.rb_node;
53 struct rb_node *parent = NULL;
54
55 while (*p != NULL) {
56 int rc;
57
58 parent = *p;
59
60 rc = rblist->node_cmp(parent, entry);
61 if (rc > 0)
62 p = &(*p)->rb_left;
63 else if (rc < 0)
64 p = &(*p)->rb_right;
65 else
66 return parent;
67 }
68
69 return NULL;
70}
71
72void rblist__init(struct rblist *rblist)
73{
74 if (rblist != NULL) {
75 rblist->entries = RB_ROOT;
76 rblist->nr_entries = 0;
77 }
78
79 return;
80}
81
82void rblist__delete(struct rblist *rblist)
83{
84 if (rblist != NULL) {
85 struct rb_node *pos, *next = rb_first(&rblist->entries);
86
87 while (next) {
88 pos = next;
89 next = rb_next(pos);
90 rb_erase(pos, &rblist->entries);
91 rblist->node_delete(rblist, pos);
92 }
93 free(rblist);
94 }
95}
96
97struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
98{
99 struct rb_node *node;
100
101 for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {
102 if (!idx--)
103 return node;
104 }
105
106 return NULL;
107}
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
new file mode 100644
index 000000000000..6d0cae5ae83d
--- /dev/null
+++ b/tools/perf/util/rblist.h
@@ -0,0 +1,47 @@
1#ifndef __PERF_RBLIST_H
2#define __PERF_RBLIST_H
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7/*
8 * create node structs of the form:
9 * struct my_node {
10 * struct rb_node rb_node;
11 * ... my data ...
12 * };
13 *
14 * create list structs of the form:
15 * struct mylist {
16 * struct rblist rblist;
17 * ... my data ...
18 * };
19 */
20
21struct rblist {
22 struct rb_root entries;
23 unsigned int nr_entries;
24
25 int (*node_cmp)(struct rb_node *rbn, const void *entry);
26 struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);
27 void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);
28};
29
30void rblist__init(struct rblist *rblist);
31void rblist__delete(struct rblist *rblist);
32int rblist__add_node(struct rblist *rblist, const void *new_entry);
33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
34struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
36
37static inline bool rblist__empty(const struct rblist *rblist)
38{
39 return rblist->nr_entries == 0;
40}
41
42static inline unsigned int rblist__nr_entries(const struct rblist *rblist)
43{
44 return rblist->nr_entries;
45}
46
47#endif /* __PERF_RBLIST_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8e485592ca20..2437fb0b463a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -80,13 +80,12 @@ out_close:
80 return -1; 80 return -1;
81} 81}
82 82
83void perf_session__update_sample_type(struct perf_session *self) 83void perf_session__set_id_hdr_size(struct perf_session *session)
84{ 84{
85 self->sample_type = perf_evlist__sample_type(self->evlist); 85 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
86 self->sample_size = __perf_evsel__sample_size(self->sample_type); 86
87 self->sample_id_all = perf_evlist__sample_id_all(self->evlist); 87 session->host_machine.id_hdr_size = id_hdr_size;
88 self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); 88 machines__set_id_hdr_size(&session->machines, id_hdr_size);
89 self->host_machine.id_hdr_size = self->id_hdr_size;
90} 89}
91 90
92int perf_session__create_kernel_maps(struct perf_session *self) 91int perf_session__create_kernel_maps(struct perf_session *self)
@@ -146,7 +145,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
146 if (mode == O_RDONLY) { 145 if (mode == O_RDONLY) {
147 if (perf_session__open(self, force) < 0) 146 if (perf_session__open(self, force) < 0)
148 goto out_delete; 147 goto out_delete;
149 perf_session__update_sample_type(self); 148 perf_session__set_id_hdr_size(self);
150 } else if (mode == O_WRONLY) { 149 } else if (mode == O_WRONLY) {
151 /* 150 /*
152 * In O_RDONLY mode this will be performed when reading the 151 * In O_RDONLY mode this will be performed when reading the
@@ -157,7 +156,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
157 } 156 }
158 157
159 if (tool && tool->ordering_requires_timestamps && 158 if (tool && tool->ordering_requires_timestamps &&
160 tool->ordered_samples && !self->sample_id_all) { 159 tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) {
161 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 160 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
162 tool->ordered_samples = false; 161 tool->ordered_samples = false;
163 } 162 }
@@ -672,7 +671,8 @@ static void flush_sample_queue(struct perf_session *s,
672 if (iter->timestamp > limit) 671 if (iter->timestamp > limit)
673 break; 672 break;
674 673
675 ret = perf_session__parse_sample(s, iter->event, &sample); 674 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
675 s->header.needs_swap);
676 if (ret) 676 if (ret)
677 pr_err("Can't parse sample, err = %d\n", ret); 677 pr_err("Can't parse sample, err = %d\n", ret);
678 else 678 else
@@ -864,16 +864,18 @@ static void perf_session__print_tstamp(struct perf_session *session,
864 union perf_event *event, 864 union perf_event *event,
865 struct perf_sample *sample) 865 struct perf_sample *sample)
866{ 866{
867 u64 sample_type = perf_evlist__sample_type(session->evlist);
868
867 if (event->header.type != PERF_RECORD_SAMPLE && 869 if (event->header.type != PERF_RECORD_SAMPLE &&
868 !session->sample_id_all) { 870 !perf_evlist__sample_id_all(session->evlist)) {
869 fputs("-1 -1 ", stdout); 871 fputs("-1 -1 ", stdout);
870 return; 872 return;
871 } 873 }
872 874
873 if ((session->sample_type & PERF_SAMPLE_CPU)) 875 if ((sample_type & PERF_SAMPLE_CPU))
874 printf("%u ", sample->cpu); 876 printf("%u ", sample->cpu);
875 877
876 if (session->sample_type & PERF_SAMPLE_TIME) 878 if (sample_type & PERF_SAMPLE_TIME)
877 printf("%" PRIu64 " ", sample->time); 879 printf("%" PRIu64 " ", sample->time);
878} 880}
879 881
@@ -898,6 +900,8 @@ static void dump_event(struct perf_session *session, union perf_event *event,
898static void dump_sample(struct perf_session *session, union perf_event *event, 900static void dump_sample(struct perf_session *session, union perf_event *event,
899 struct perf_sample *sample) 901 struct perf_sample *sample)
900{ 902{
903 u64 sample_type;
904
901 if (!dump_trace) 905 if (!dump_trace)
902 return; 906 return;
903 907
@@ -905,10 +909,12 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
905 event->header.misc, sample->pid, sample->tid, sample->ip, 909 event->header.misc, sample->pid, sample->tid, sample->ip,
906 sample->period, sample->addr); 910 sample->period, sample->addr);
907 911
908 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 912 sample_type = perf_evlist__sample_type(session->evlist);
913
914 if (sample_type & PERF_SAMPLE_CALLCHAIN)
909 callchain__printf(sample); 915 callchain__printf(sample);
910 916
911 if (session->sample_type & PERF_SAMPLE_BRANCH_STACK) 917 if (sample_type & PERF_SAMPLE_BRANCH_STACK)
912 branch_stack__printf(sample); 918 branch_stack__printf(sample);
913} 919}
914 920
@@ -918,7 +924,9 @@ static struct machine *
918{ 924{
919 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 925 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
920 926
921 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 927 if (perf_guest &&
928 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
929 (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
922 u32 pid; 930 u32 pid;
923 931
924 if (event->header.type == PERF_RECORD_MMAP) 932 if (event->header.type == PERF_RECORD_MMAP)
@@ -1003,7 +1011,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1003 union perf_event *event, struct perf_sample *sample) 1011 union perf_event *event, struct perf_sample *sample)
1004{ 1012{
1005 if (event->header.type != PERF_RECORD_SAMPLE || 1013 if (event->header.type != PERF_RECORD_SAMPLE ||
1006 !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) 1014 !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
1007 return 0; 1015 return 0;
1008 1016
1009 if (!ip_callchain__valid(sample->callchain, event)) { 1017 if (!ip_callchain__valid(sample->callchain, event)) {
@@ -1027,7 +1035,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
1027 case PERF_RECORD_HEADER_ATTR: 1035 case PERF_RECORD_HEADER_ATTR:
1028 err = tool->attr(event, &session->evlist); 1036 err = tool->attr(event, &session->evlist);
1029 if (err == 0) 1037 if (err == 0)
1030 perf_session__update_sample_type(session); 1038 perf_session__set_id_hdr_size(session);
1031 return err; 1039 return err;
1032 case PERF_RECORD_HEADER_EVENT_TYPE: 1040 case PERF_RECORD_HEADER_EVENT_TYPE:
1033 return tool->event_type(tool, event); 1041 return tool->event_type(tool, event);
@@ -1062,7 +1070,7 @@ static int perf_session__process_event(struct perf_session *session,
1062 int ret; 1070 int ret;
1063 1071
1064 if (session->header.needs_swap) 1072 if (session->header.needs_swap)
1065 event_swap(event, session->sample_id_all); 1073 event_swap(event, perf_evlist__sample_id_all(session->evlist));
1066 1074
1067 if (event->header.type >= PERF_RECORD_HEADER_MAX) 1075 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1068 return -EINVAL; 1076 return -EINVAL;
@@ -1075,7 +1083,8 @@ static int perf_session__process_event(struct perf_session *session,
1075 /* 1083 /*
1076 * For all kernel events we get the sample data 1084 * For all kernel events we get the sample data
1077 */ 1085 */
1078 ret = perf_session__parse_sample(session, event, &sample); 1086 ret = perf_evlist__parse_sample(session->evlist, event, &sample,
1087 session->header.needs_swap);
1079 if (ret) 1088 if (ret)
1080 return ret; 1089 return ret;
1081 1090
@@ -1386,9 +1395,9 @@ int perf_session__process_events(struct perf_session *self,
1386 return err; 1395 return err;
1387} 1396}
1388 1397
1389bool perf_session__has_traces(struct perf_session *self, const char *msg) 1398bool perf_session__has_traces(struct perf_session *session, const char *msg)
1390{ 1399{
1391 if (!(self->sample_type & PERF_SAMPLE_RAW)) { 1400 if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) {
1392 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); 1401 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
1393 return false; 1402 return false;
1394 } 1403 }
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 7c435bde6eb0..1f7ec87db7d7 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -41,13 +41,9 @@ struct perf_session {
41 * perf.data file. 41 * perf.data file.
42 */ 42 */
43 struct hists hists; 43 struct hists hists;
44 u64 sample_type;
45 int sample_size;
46 int fd; 44 int fd;
47 bool fd_pipe; 45 bool fd_pipe;
48 bool repipe; 46 bool repipe;
49 bool sample_id_all;
50 u16 id_hdr_size;
51 int cwdlen; 47 int cwdlen;
52 char *cwd; 48 char *cwd;
53 struct ordered_samples ordered_samples; 49 struct ordered_samples ordered_samples;
@@ -86,7 +82,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
86 82
87int perf_session__create_kernel_maps(struct perf_session *self); 83int perf_session__create_kernel_maps(struct perf_session *self);
88 84
89void perf_session__update_sample_type(struct perf_session *self); 85void perf_session__set_id_hdr_size(struct perf_session *session);
90void perf_session__remove_thread(struct perf_session *self, struct thread *th); 86void perf_session__remove_thread(struct perf_session *self, struct thread *th);
91 87
92static inline 88static inline
@@ -130,24 +126,6 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
130 126
131size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 127size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
132 128
133static inline int perf_session__parse_sample(struct perf_session *session,
134 const union perf_event *event,
135 struct perf_sample *sample)
136{
137 return perf_event__parse_sample(event, session->sample_type,
138 session->sample_size,
139 session->sample_id_all, sample,
140 session->header.needs_swap);
141}
142
143static inline int perf_session__synthesize_sample(struct perf_session *session,
144 union perf_event *event,
145 const struct perf_sample *sample)
146{
147 return perf_event__synthesize_sample(event, session->sample_type,
148 sample, session->header.needs_swap);
149}
150
151struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 129struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
152 unsigned int type); 130 unsigned int type);
153 131
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 6783a2043555..95856ff3dda4 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -10,23 +10,28 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <string.h> 11#include <string.h>
12 12
13static struct str_node *str_node__new(const char *s, bool dupstr) 13static
14struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
14{ 15{
15 struct str_node *self = malloc(sizeof(*self)); 16 const char *s = entry;
17 struct rb_node *rc = NULL;
18 struct strlist *strlist = container_of(rblist, struct strlist, rblist);
19 struct str_node *snode = malloc(sizeof(*snode));
16 20
17 if (self != NULL) { 21 if (snode != NULL) {
18 if (dupstr) { 22 if (strlist->dupstr) {
19 s = strdup(s); 23 s = strdup(s);
20 if (s == NULL) 24 if (s == NULL)
21 goto out_delete; 25 goto out_delete;
22 } 26 }
23 self->s = s; 27 snode->s = s;
28 rc = &snode->rb_node;
24 } 29 }
25 30
26 return self; 31 return rc;
27 32
28out_delete: 33out_delete:
29 free(self); 34 free(snode);
30 return NULL; 35 return NULL;
31} 36}
32 37
@@ -37,36 +42,26 @@ static void str_node__delete(struct str_node *self, bool dupstr)
37 free(self); 42 free(self);
38} 43}
39 44
40int strlist__add(struct strlist *self, const char *new_entry) 45static
46void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
41{ 47{
42 struct rb_node **p = &self->entries.rb_node; 48 struct strlist *slist = container_of(rblist, struct strlist, rblist);
43 struct rb_node *parent = NULL; 49 struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
44 struct str_node *sn;
45
46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
60 50
61 sn = str_node__new(new_entry, self->dupstr); 51 str_node__delete(snode, slist->dupstr);
62 if (sn == NULL) 52}
63 return -ENOMEM;
64 53
65 rb_link_node(&sn->rb_node, parent, p); 54static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
66 rb_insert_color(&sn->rb_node, &self->entries); 55{
67 ++self->nr_entries; 56 const char *str = entry;
57 struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
58
59 return strcmp(snode->s, str);
60}
68 61
69 return 0; 62int strlist__add(struct strlist *self, const char *new_entry)
63{
64 return rblist__add_node(&self->rblist, new_entry);
70} 65}
71 66
72int strlist__load(struct strlist *self, const char *filename) 67int strlist__load(struct strlist *self, const char *filename)
@@ -96,34 +91,20 @@ out:
96 return err; 91 return err;
97} 92}
98 93
99void strlist__remove(struct strlist *self, struct str_node *sn) 94void strlist__remove(struct strlist *slist, struct str_node *snode)
100{ 95{
101 rb_erase(&sn->rb_node, &self->entries); 96 str_node__delete(snode, slist->dupstr);
102 str_node__delete(sn, self->dupstr);
103} 97}
104 98
105struct str_node *strlist__find(struct strlist *self, const char *entry) 99struct str_node *strlist__find(struct strlist *slist, const char *entry)
106{ 100{
107 struct rb_node **p = &self->entries.rb_node; 101 struct str_node *snode = NULL;
108 struct rb_node *parent = NULL; 102 struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
109
110 while (*p != NULL) {
111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return sn;
124 }
125 103
126 return NULL; 104 if (rb_node)
105 snode = container_of(rb_node, struct str_node, rb_node);
106
107 return snode;
127} 108}
128 109
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 110static int strlist__parse_list_entry(struct strlist *self, const char *s)
@@ -156,9 +137,12 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
156 struct strlist *self = malloc(sizeof(*self)); 137 struct strlist *self = malloc(sizeof(*self));
157 138
158 if (self != NULL) { 139 if (self != NULL) {
159 self->entries = RB_ROOT; 140 rblist__init(&self->rblist);
141 self->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete;
144
160 self->dupstr = dupstr; 145 self->dupstr = dupstr;
161 self->nr_entries = 0;
162 if (slist && strlist__parse_list(self, slist) != 0) 146 if (slist && strlist__parse_list(self, slist) != 0)
163 goto out_error; 147 goto out_error;
164 } 148 }
@@ -171,30 +155,18 @@ out_error:
171 155
172void strlist__delete(struct strlist *self) 156void strlist__delete(struct strlist *self)
173{ 157{
174 if (self != NULL) { 158 if (self != NULL)
175 struct str_node *pos; 159 rblist__delete(&self->rblist);
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
186} 160}
187 161
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx) 162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
189{ 163{
190 struct rb_node *nd; 164 struct str_node *snode = NULL;
165 struct rb_node *rb_node;
191 166
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 167 rb_node = rblist__entry(&slist->rblist, idx);
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node); 168 if (rb_node)
169 snode = container_of(rb_node, struct str_node, rb_node);
194 170
195 if (!idx--) 171 return snode;
196 return pos;
197 }
198
199 return NULL;
200} 172}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 3ba839007d2c..dd9f922ec67c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -4,14 +4,15 @@
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "rblist.h"
8
7struct str_node { 9struct str_node {
8 struct rb_node rb_node; 10 struct rb_node rb_node;
9 const char *s; 11 const char *s;
10}; 12};
11 13
12struct strlist { 14struct strlist {
13 struct rb_root entries; 15 struct rblist rblist;
14 unsigned int nr_entries;
15 bool dupstr; 16 bool dupstr;
16}; 17};
17 18
@@ -32,18 +33,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry)
32 33
33static inline bool strlist__empty(const struct strlist *self) 34static inline bool strlist__empty(const struct strlist *self)
34{ 35{
35 return self->nr_entries == 0; 36 return rblist__empty(&self->rblist);
36} 37}
37 38
38static inline unsigned int strlist__nr_entries(const struct strlist *self) 39static inline unsigned int strlist__nr_entries(const struct strlist *self)
39{ 40{
40 return self->nr_entries; 41 return rblist__nr_entries(&self->rblist);
41} 42}
42 43
43/* For strlist iteration */ 44/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self) 45static inline struct str_node *strlist__first(struct strlist *self)
45{ 46{
46 struct rb_node *rn = rb_first(&self->entries); 47 struct rb_node *rn = rb_first(&self->rblist.entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48} 49}
49static inline struct str_node *strlist__next(struct str_node *sn) 50static inline struct str_node *strlist__next(struct str_node *sn)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 50958bbeb26a..8b63b678e127 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,6 +29,7 @@
29#define NT_GNU_BUILD_ID 3 29#define NT_GNU_BUILD_ID 3
30#endif 30#endif
31 31
32static void dso_cache__free(struct rb_root *root);
32static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); 33static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
33static int elf_read_build_id(Elf *elf, void *bf, size_t size); 34static int elf_read_build_id(Elf *elf, void *bf, size_t size);
34static void dsos__add(struct list_head *head, struct dso *dso); 35static void dsos__add(struct list_head *head, struct dso *dso);
@@ -48,6 +49,31 @@ struct symbol_conf symbol_conf = {
48 .symfs = "", 49 .symfs = "",
49}; 50};
50 51
52static enum dso_binary_type binary_type_symtab[] = {
53 DSO_BINARY_TYPE__KALLSYMS,
54 DSO_BINARY_TYPE__GUEST_KALLSYMS,
55 DSO_BINARY_TYPE__JAVA_JIT,
56 DSO_BINARY_TYPE__DEBUGLINK,
57 DSO_BINARY_TYPE__BUILD_ID_CACHE,
58 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
59 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
60 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
61 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
62 DSO_BINARY_TYPE__GUEST_KMODULE,
63 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
64 DSO_BINARY_TYPE__NOT_FOUND,
65};
66
67#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
68
69static enum dso_binary_type binary_type_data[] = {
70 DSO_BINARY_TYPE__BUILD_ID_CACHE,
71 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
72 DSO_BINARY_TYPE__NOT_FOUND,
73};
74
75#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
76
51int dso__name_len(const struct dso *dso) 77int dso__name_len(const struct dso *dso)
52{ 78{
53 if (!dso) 79 if (!dso)
@@ -318,7 +344,9 @@ struct dso *dso__new(const char *name)
318 dso__set_short_name(dso, dso->name); 344 dso__set_short_name(dso, dso->name);
319 for (i = 0; i < MAP__NR_TYPES; ++i) 345 for (i = 0; i < MAP__NR_TYPES; ++i)
320 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 346 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
321 dso->symtab_type = SYMTAB__NOT_FOUND; 347 dso->cache = RB_ROOT;
348 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
349 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
322 dso->loaded = 0; 350 dso->loaded = 0;
323 dso->sorted_by_name = 0; 351 dso->sorted_by_name = 0;
324 dso->has_build_id = 0; 352 dso->has_build_id = 0;
@@ -352,6 +380,7 @@ void dso__delete(struct dso *dso)
352 free((char *)dso->short_name); 380 free((char *)dso->short_name);
353 if (dso->lname_alloc) 381 if (dso->lname_alloc)
354 free(dso->long_name); 382 free(dso->long_name);
383 dso_cache__free(&dso->cache);
355 free(dso); 384 free(dso);
356} 385}
357 386
@@ -806,9 +835,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
806 symbols__fixup_end(&dso->symbols[map->type]); 835 symbols__fixup_end(&dso->symbols[map->type]);
807 836
808 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 837 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
809 dso->symtab_type = SYMTAB__GUEST_KALLSYMS; 838 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
810 else 839 else
811 dso->symtab_type = SYMTAB__KALLSYMS; 840 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
812 841
813 return dso__split_kallsyms(dso, map, filter); 842 return dso__split_kallsyms(dso, map, filter);
814} 843}
@@ -1660,32 +1689,110 @@ out:
1660char dso__symtab_origin(const struct dso *dso) 1689char dso__symtab_origin(const struct dso *dso)
1661{ 1690{
1662 static const char origin[] = { 1691 static const char origin[] = {
1663 [SYMTAB__KALLSYMS] = 'k', 1692 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
1664 [SYMTAB__JAVA_JIT] = 'j', 1693 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
1665 [SYMTAB__DEBUGLINK] = 'l', 1694 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
1666 [SYMTAB__BUILD_ID_CACHE] = 'B', 1695 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
1667 [SYMTAB__FEDORA_DEBUGINFO] = 'f', 1696 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
1668 [SYMTAB__UBUNTU_DEBUGINFO] = 'u', 1697 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
1669 [SYMTAB__BUILDID_DEBUGINFO] = 'b', 1698 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
1670 [SYMTAB__SYSTEM_PATH_DSO] = 'd', 1699 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
1671 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', 1700 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
1672 [SYMTAB__GUEST_KALLSYMS] = 'g', 1701 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
1673 [SYMTAB__GUEST_KMODULE] = 'G', 1702 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
1674 }; 1703 };
1675 1704
1676 if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) 1705 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
1677 return '!'; 1706 return '!';
1678 return origin[dso->symtab_type]; 1707 return origin[dso->symtab_type];
1679} 1708}
1680 1709
1710int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
1711 char *root_dir, char *file, size_t size)
1712{
1713 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1714 int ret = 0;
1715
1716 switch (type) {
1717 case DSO_BINARY_TYPE__DEBUGLINK: {
1718 char *debuglink;
1719
1720 strncpy(file, dso->long_name, size);
1721 debuglink = file + dso->long_name_len;
1722 while (debuglink != file && *debuglink != '/')
1723 debuglink--;
1724 if (*debuglink == '/')
1725 debuglink++;
1726 filename__read_debuglink(dso->long_name, debuglink,
1727 size - (debuglink - file));
1728 }
1729 break;
1730 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1731 /* skip the locally configured cache if a symfs is given */
1732 if (symbol_conf.symfs[0] ||
1733 (dso__build_id_filename(dso, file, size) == NULL))
1734 ret = -1;
1735 break;
1736
1737 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1738 snprintf(file, size, "%s/usr/lib/debug%s.debug",
1739 symbol_conf.symfs, dso->long_name);
1740 break;
1741
1742 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1743 snprintf(file, size, "%s/usr/lib/debug%s",
1744 symbol_conf.symfs, dso->long_name);
1745 break;
1746
1747 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1748 if (!dso->has_build_id) {
1749 ret = -1;
1750 break;
1751 }
1752
1753 build_id__sprintf(dso->build_id,
1754 sizeof(dso->build_id),
1755 build_id_hex);
1756 snprintf(file, size,
1757 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1758 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1759 break;
1760
1761 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1762 snprintf(file, size, "%s%s",
1763 symbol_conf.symfs, dso->long_name);
1764 break;
1765
1766 case DSO_BINARY_TYPE__GUEST_KMODULE:
1767 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
1768 root_dir, dso->long_name);
1769 break;
1770
1771 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1772 snprintf(file, size, "%s%s", symbol_conf.symfs,
1773 dso->long_name);
1774 break;
1775
1776 default:
1777 case DSO_BINARY_TYPE__KALLSYMS:
1778 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1779 case DSO_BINARY_TYPE__JAVA_JIT:
1780 case DSO_BINARY_TYPE__NOT_FOUND:
1781 ret = -1;
1782 break;
1783 }
1784
1785 return ret;
1786}
1787
1681int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 1788int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1682{ 1789{
1683 int size = PATH_MAX;
1684 char *name; 1790 char *name;
1685 int ret = -1; 1791 int ret = -1;
1686 int fd; 1792 int fd;
1793 u_int i;
1687 struct machine *machine; 1794 struct machine *machine;
1688 const char *root_dir; 1795 char *root_dir = (char *) "";
1689 int want_symtab; 1796 int want_symtab;
1690 1797
1691 dso__set_loaded(dso, map->type); 1798 dso__set_loaded(dso, map->type);
@@ -1700,7 +1807,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1700 else 1807 else
1701 machine = NULL; 1808 machine = NULL;
1702 1809
1703 name = malloc(size); 1810 name = malloc(PATH_MAX);
1704 if (!name) 1811 if (!name)
1705 return -1; 1812 return -1;
1706 1813
@@ -1719,81 +1826,27 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1719 } 1826 }
1720 1827
1721 ret = dso__load_perf_map(dso, map, filter); 1828 ret = dso__load_perf_map(dso, map, filter);
1722 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : 1829 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
1723 SYMTAB__NOT_FOUND; 1830 DSO_BINARY_TYPE__NOT_FOUND;
1724 return ret; 1831 return ret;
1725 } 1832 }
1726 1833
1834 if (machine)
1835 root_dir = machine->root_dir;
1836
1727 /* Iterate over candidate debug images. 1837 /* Iterate over candidate debug images.
1728 * On the first pass, only load images if they have a full symtab. 1838 * On the first pass, only load images if they have a full symtab.
1729 * Failing that, do a second pass where we accept .dynsym also 1839 * Failing that, do a second pass where we accept .dynsym also
1730 */ 1840 */
1731 want_symtab = 1; 1841 want_symtab = 1;
1732restart: 1842restart:
1733 for (dso->symtab_type = SYMTAB__DEBUGLINK; 1843 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
1734 dso->symtab_type != SYMTAB__NOT_FOUND;
1735 dso->symtab_type++) {
1736 switch (dso->symtab_type) {
1737 case SYMTAB__DEBUGLINK: {
1738 char *debuglink;
1739 strncpy(name, dso->long_name, size);
1740 debuglink = name + dso->long_name_len;
1741 while (debuglink != name && *debuglink != '/')
1742 debuglink--;
1743 if (*debuglink == '/')
1744 debuglink++;
1745 filename__read_debuglink(dso->long_name, debuglink,
1746 size - (debuglink - name));
1747 }
1748 break;
1749 case SYMTAB__BUILD_ID_CACHE:
1750 /* skip the locally configured cache if a symfs is given */
1751 if (symbol_conf.symfs[0] ||
1752 (dso__build_id_filename(dso, name, size) == NULL)) {
1753 continue;
1754 }
1755 break;
1756 case SYMTAB__FEDORA_DEBUGINFO:
1757 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1758 symbol_conf.symfs, dso->long_name);
1759 break;
1760 case SYMTAB__UBUNTU_DEBUGINFO:
1761 snprintf(name, size, "%s/usr/lib/debug%s",
1762 symbol_conf.symfs, dso->long_name);
1763 break;
1764 case SYMTAB__BUILDID_DEBUGINFO: {
1765 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1766 1844
1767 if (!dso->has_build_id) 1845 dso->symtab_type = binary_type_symtab[i];
1768 continue;
1769 1846
1770 build_id__sprintf(dso->build_id, 1847 if (dso__binary_type_file(dso, dso->symtab_type,
1771 sizeof(dso->build_id), 1848 root_dir, name, PATH_MAX))
1772 build_id_hex); 1849 continue;
1773 snprintf(name, size,
1774 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1775 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1776 }
1777 break;
1778 case SYMTAB__SYSTEM_PATH_DSO:
1779 snprintf(name, size, "%s%s",
1780 symbol_conf.symfs, dso->long_name);
1781 break;
1782 case SYMTAB__GUEST_KMODULE:
1783 if (map->groups && machine)
1784 root_dir = machine->root_dir;
1785 else
1786 root_dir = "";
1787 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1788 root_dir, dso->long_name);
1789 break;
1790
1791 case SYMTAB__SYSTEM_PATH_KMODULE:
1792 snprintf(name, size, "%s%s", symbol_conf.symfs,
1793 dso->long_name);
1794 break;
1795 default:;
1796 }
1797 1850
1798 /* Name is now the name of the next image to try */ 1851 /* Name is now the name of the next image to try */
1799 fd = open(name, O_RDONLY); 1852 fd = open(name, O_RDONLY);
@@ -2010,9 +2063,9 @@ struct map *machine__new_module(struct machine *machine, u64 start,
2010 return NULL; 2063 return NULL;
2011 2064
2012 if (machine__is_host(machine)) 2065 if (machine__is_host(machine))
2013 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; 2066 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
2014 else 2067 else
2015 dso->symtab_type = SYMTAB__GUEST_KMODULE; 2068 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
2016 map_groups__insert(&machine->kmaps, map); 2069 map_groups__insert(&machine->kmaps, map);
2017 return map; 2070 return map;
2018} 2071}
@@ -2564,8 +2617,15 @@ int machine__create_kernel_maps(struct machine *machine)
2564 __machine__create_kernel_maps(machine, kernel) < 0) 2617 __machine__create_kernel_maps(machine, kernel) < 0)
2565 return -1; 2618 return -1;
2566 2619
2567 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) 2620 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
2568 pr_debug("Problems creating module maps, continuing anyway...\n"); 2621 if (machine__is_host(machine))
2622 pr_debug("Problems creating module maps, "
2623 "continuing anyway...\n");
2624 else
2625 pr_debug("Problems creating module maps for guest %d, "
2626 "continuing anyway...\n", machine->pid);
2627 }
2628
2569 /* 2629 /*
2570 * Now that we have all the maps created, just set the ->end of them: 2630 * Now that we have all the maps created, just set the ->end of them:
2571 */ 2631 */
@@ -2815,6 +2875,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
2815 int i, items = 0; 2875 int i, items = 0;
2816 char path[PATH_MAX]; 2876 char path[PATH_MAX];
2817 pid_t pid; 2877 pid_t pid;
2878 char *endp;
2818 2879
2819 if (symbol_conf.default_guest_vmlinux_name || 2880 if (symbol_conf.default_guest_vmlinux_name ||
2820 symbol_conf.default_guest_modules || 2881 symbol_conf.default_guest_modules ||
@@ -2831,7 +2892,14 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
2831 /* Filter out . and .. */ 2892 /* Filter out . and .. */
2832 continue; 2893 continue;
2833 } 2894 }
2834 pid = atoi(namelist[i]->d_name); 2895 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
2896 if ((*endp != '\0') ||
2897 (endp == namelist[i]->d_name) ||
2898 (errno == ERANGE)) {
2899 pr_debug("invalid directory (%s). Skipping.\n",
2900 namelist[i]->d_name);
2901 continue;
2902 }
2835 sprintf(path, "%s/%s/proc/kallsyms", 2903 sprintf(path, "%s/%s/proc/kallsyms",
2836 symbol_conf.guestmount, 2904 symbol_conf.guestmount,
2837 namelist[i]->d_name); 2905 namelist[i]->d_name);
@@ -2905,3 +2973,218 @@ struct map *dso__new_map(const char *name)
2905 2973
2906 return map; 2974 return map;
2907} 2975}
2976
2977static int open_dso(struct dso *dso, struct machine *machine)
2978{
2979 char *root_dir = (char *) "";
2980 char *name;
2981 int fd;
2982
2983 name = malloc(PATH_MAX);
2984 if (!name)
2985 return -ENOMEM;
2986
2987 if (machine)
2988 root_dir = machine->root_dir;
2989
2990 if (dso__binary_type_file(dso, dso->data_type,
2991 root_dir, name, PATH_MAX)) {
2992 free(name);
2993 return -EINVAL;
2994 }
2995
2996 fd = open(name, O_RDONLY);
2997 free(name);
2998 return fd;
2999}
3000
3001int dso__data_fd(struct dso *dso, struct machine *machine)
3002{
3003 int i = 0;
3004
3005 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
3006 return open_dso(dso, machine);
3007
3008 do {
3009 int fd;
3010
3011 dso->data_type = binary_type_data[i++];
3012
3013 fd = open_dso(dso, machine);
3014 if (fd >= 0)
3015 return fd;
3016
3017 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
3018
3019 return -EINVAL;
3020}
3021
3022static void
3023dso_cache__free(struct rb_root *root)
3024{
3025 struct rb_node *next = rb_first(root);
3026
3027 while (next) {
3028 struct dso_cache *cache;
3029
3030 cache = rb_entry(next, struct dso_cache, rb_node);
3031 next = rb_next(&cache->rb_node);
3032 rb_erase(&cache->rb_node, root);
3033 free(cache);
3034 }
3035}
3036
3037static struct dso_cache*
3038dso_cache__find(struct rb_root *root, u64 offset)
3039{
3040 struct rb_node **p = &root->rb_node;
3041 struct rb_node *parent = NULL;
3042 struct dso_cache *cache;
3043
3044 while (*p != NULL) {
3045 u64 end;
3046
3047 parent = *p;
3048 cache = rb_entry(parent, struct dso_cache, rb_node);
3049 end = cache->offset + DSO__DATA_CACHE_SIZE;
3050
3051 if (offset < cache->offset)
3052 p = &(*p)->rb_left;
3053 else if (offset >= end)
3054 p = &(*p)->rb_right;
3055 else
3056 return cache;
3057 }
3058 return NULL;
3059}
3060
3061static void
3062dso_cache__insert(struct rb_root *root, struct dso_cache *new)
3063{
3064 struct rb_node **p = &root->rb_node;
3065 struct rb_node *parent = NULL;
3066 struct dso_cache *cache;
3067 u64 offset = new->offset;
3068
3069 while (*p != NULL) {
3070 u64 end;
3071
3072 parent = *p;
3073 cache = rb_entry(parent, struct dso_cache, rb_node);
3074 end = cache->offset + DSO__DATA_CACHE_SIZE;
3075
3076 if (offset < cache->offset)
3077 p = &(*p)->rb_left;
3078 else if (offset >= end)
3079 p = &(*p)->rb_right;
3080 }
3081
3082 rb_link_node(&new->rb_node, parent, p);
3083 rb_insert_color(&new->rb_node, root);
3084}
3085
3086static ssize_t
3087dso_cache__memcpy(struct dso_cache *cache, u64 offset,
3088 u8 *data, u64 size)
3089{
3090 u64 cache_offset = offset - cache->offset;
3091 u64 cache_size = min(cache->size - cache_offset, size);
3092
3093 memcpy(data, cache->data + cache_offset, cache_size);
3094 return cache_size;
3095}
3096
3097static ssize_t
3098dso_cache__read(struct dso *dso, struct machine *machine,
3099 u64 offset, u8 *data, ssize_t size)
3100{
3101 struct dso_cache *cache;
3102 ssize_t ret;
3103 int fd;
3104
3105 fd = dso__data_fd(dso, machine);
3106 if (fd < 0)
3107 return -1;
3108
3109 do {
3110 u64 cache_offset;
3111
3112 ret = -ENOMEM;
3113
3114 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
3115 if (!cache)
3116 break;
3117
3118 cache_offset = offset & DSO__DATA_CACHE_MASK;
3119 ret = -EINVAL;
3120
3121 if (-1 == lseek(fd, cache_offset, SEEK_SET))
3122 break;
3123
3124 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
3125 if (ret <= 0)
3126 break;
3127
3128 cache->offset = cache_offset;
3129 cache->size = ret;
3130 dso_cache__insert(&dso->cache, cache);
3131
3132 ret = dso_cache__memcpy(cache, offset, data, size);
3133
3134 } while (0);
3135
3136 if (ret <= 0)
3137 free(cache);
3138
3139 close(fd);
3140 return ret;
3141}
3142
3143static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
3144 u64 offset, u8 *data, ssize_t size)
3145{
3146 struct dso_cache *cache;
3147
3148 cache = dso_cache__find(&dso->cache, offset);
3149 if (cache)
3150 return dso_cache__memcpy(cache, offset, data, size);
3151 else
3152 return dso_cache__read(dso, machine, offset, data, size);
3153}
3154
3155ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
3156 u64 offset, u8 *data, ssize_t size)
3157{
3158 ssize_t r = 0;
3159 u8 *p = data;
3160
3161 do {
3162 ssize_t ret;
3163
3164 ret = dso_cache_read(dso, machine, offset, p, size);
3165 if (ret < 0)
3166 return ret;
3167
3168 /* Reached EOF, return what we have. */
3169 if (!ret)
3170 break;
3171
3172 BUG_ON(ret > size);
3173
3174 r += ret;
3175 p += ret;
3176 offset += ret;
3177 size -= ret;
3178
3179 } while (size);
3180
3181 return r;
3182}
3183
3184ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
3185 struct machine *machine, u64 addr,
3186 u8 *data, ssize_t size)
3187{
3188 u64 offset = map->map_ip(map, addr);
3189 return dso__data_read_offset(dso, machine, offset, data, size);
3190}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index a884b99017f0..1fe733a1e21f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -155,6 +155,21 @@ struct addr_location {
155 s32 cpu; 155 s32 cpu;
156}; 156};
157 157
158enum dso_binary_type {
159 DSO_BINARY_TYPE__KALLSYMS = 0,
160 DSO_BINARY_TYPE__GUEST_KALLSYMS,
161 DSO_BINARY_TYPE__JAVA_JIT,
162 DSO_BINARY_TYPE__DEBUGLINK,
163 DSO_BINARY_TYPE__BUILD_ID_CACHE,
164 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
165 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
166 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
167 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
168 DSO_BINARY_TYPE__GUEST_KMODULE,
169 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
170 DSO_BINARY_TYPE__NOT_FOUND,
171};
172
158enum dso_kernel_type { 173enum dso_kernel_type {
159 DSO_TYPE_USER = 0, 174 DSO_TYPE_USER = 0,
160 DSO_TYPE_KERNEL, 175 DSO_TYPE_KERNEL,
@@ -167,19 +182,31 @@ enum dso_swap_type {
167 DSO_SWAP__YES, 182 DSO_SWAP__YES,
168}; 183};
169 184
185#define DSO__DATA_CACHE_SIZE 4096
186#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
187
188struct dso_cache {
189 struct rb_node rb_node;
190 u64 offset;
191 u64 size;
192 char data[0];
193};
194
170struct dso { 195struct dso {
171 struct list_head node; 196 struct list_head node;
172 struct rb_root symbols[MAP__NR_TYPES]; 197 struct rb_root symbols[MAP__NR_TYPES];
173 struct rb_root symbol_names[MAP__NR_TYPES]; 198 struct rb_root symbol_names[MAP__NR_TYPES];
199 struct rb_root cache;
174 enum dso_kernel_type kernel; 200 enum dso_kernel_type kernel;
175 enum dso_swap_type needs_swap; 201 enum dso_swap_type needs_swap;
202 enum dso_binary_type symtab_type;
203 enum dso_binary_type data_type;
176 u8 adjust_symbols:1; 204 u8 adjust_symbols:1;
177 u8 has_build_id:1; 205 u8 has_build_id:1;
178 u8 hit:1; 206 u8 hit:1;
179 u8 annotate_warned:1; 207 u8 annotate_warned:1;
180 u8 sname_alloc:1; 208 u8 sname_alloc:1;
181 u8 lname_alloc:1; 209 u8 lname_alloc:1;
182 unsigned char symtab_type;
183 u8 sorted_by_name; 210 u8 sorted_by_name;
184 u8 loaded; 211 u8 loaded;
185 u8 build_id[BUILD_ID_SIZE]; 212 u8 build_id[BUILD_ID_SIZE];
@@ -253,21 +280,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
253 enum map_type type, FILE *fp); 280 enum map_type type, FILE *fp);
254size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); 281size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
255 282
256enum symtab_type {
257 SYMTAB__KALLSYMS = 0,
258 SYMTAB__GUEST_KALLSYMS,
259 SYMTAB__JAVA_JIT,
260 SYMTAB__DEBUGLINK,
261 SYMTAB__BUILD_ID_CACHE,
262 SYMTAB__FEDORA_DEBUGINFO,
263 SYMTAB__UBUNTU_DEBUGINFO,
264 SYMTAB__BUILDID_DEBUGINFO,
265 SYMTAB__SYSTEM_PATH_DSO,
266 SYMTAB__GUEST_KMODULE,
267 SYMTAB__SYSTEM_PATH_KMODULE,
268 SYMTAB__NOT_FOUND,
269};
270
271char dso__symtab_origin(const struct dso *dso); 283char dso__symtab_origin(const struct dso *dso);
272void dso__set_long_name(struct dso *dso, char *name); 284void dso__set_long_name(struct dso *dso, char *name);
273void dso__set_build_id(struct dso *dso, void *build_id); 285void dso__set_build_id(struct dso *dso, void *build_id);
@@ -304,4 +316,14 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);
304 316
305size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 317size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
306 318
319int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
320 char *root_dir, char *file, size_t size);
321
322int dso__data_fd(struct dso *dso, struct machine *machine);
323ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
324 u64 offset, u8 *data, ssize_t size);
325ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
326 struct machine *machine, u64 addr,
327 u8 *data, ssize_t size);
328int dso__test_data(void);
307#endif /* __PERF_SYMBOL */ 329#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 1064d5b148ad..051eaa68095e 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -110,8 +110,17 @@ int perf_target__strerror(struct perf_target *target, int errnum,
110 int idx; 110 int idx;
111 const char *msg; 111 const char *msg;
112 112
113 BUG_ON(buflen == 0);
114
113 if (errnum >= 0) { 115 if (errnum >= 0) {
114 strerror_r(errnum, buf, buflen); 116 const char *err = strerror_r(errnum, buf, buflen);
117
118 if (err != buf) {
119 size_t len = strlen(err);
120 char *c = mempcpy(buf, err, min(buflen - 1, len));
121 *c = '\0';
122 }
123
115 return 0; 124 return 0;
116 } 125 }
117 126
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
index fd8e1f1297aa..f85649554191 100644
--- a/tools/power/x86/turbostat/Makefile
+++ b/tools/power/x86/turbostat/Makefile
@@ -1,4 +1,5 @@
1turbostat : turbostat.c 1turbostat : turbostat.c
2CFLAGS += -Wall
2 3
3clean : 4clean :
4 rm -f turbostat 5 rm -f turbostat
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index adf175f61496..74e44507dfe9 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -27,7 +27,11 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs.
27on processors that additionally support C-state residency counters. 27on processors that additionally support C-state residency counters.
28 28
29.SS Options 29.SS Options
30The \fB-s\fP option prints only a 1-line summary for each sample interval. 30The \fB-s\fP option limits output to a 1-line system summary for each interval.
31.PP
32The \fB-c\fP option limits output to the 1st thread in each core.
33.PP
34The \fB-p\fP option limits output to the 1st thread in each package.
31.PP 35.PP
32The \fB-v\fP option increases verbosity. 36The \fB-v\fP option increases verbosity.
33.PP 37.PP
@@ -65,19 +69,19 @@ Subsequent rows show per-CPU statistics.
65.nf 69.nf
66[root@x980]# ./turbostat 70[root@x980]# ./turbostat
67cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 71cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
68 0.60 1.63 3.38 2.91 0.00 96.49 0.00 76.64 72 0.09 1.62 3.38 1.83 0.32 97.76 1.26 83.61
69 0 0 0.59 1.62 3.38 4.51 0.00 94.90 0.00 76.64 73 0 0 0.15 1.62 3.38 10.23 0.05 89.56 1.26 83.61
70 0 6 1.13 1.64 3.38 3.97 0.00 94.90 0.00 76.64 74 0 6 0.05 1.62 3.38 10.34
71 1 2 0.08 1.62 3.38 0.07 0.00 99.85 0.00 76.64 75 1 2 0.03 1.62 3.38 0.07 0.05 99.86
72 1 8 0.03 1.62 3.38 0.12 0.00 99.85 0.00 76.64 76 1 8 0.03 1.62 3.38 0.06
73 2 4 0.01 1.62 3.38 0.06 0.00 99.93 0.00 76.64 77 2 4 0.21 1.62 3.38 0.10 1.49 98.21
74 2 10 0.04 1.62 3.38 0.02 0.00 99.93 0.00 76.64 78 2 10 0.02 1.62 3.38 0.29
75 8 1 2.85 1.62 3.38 11.71 0.00 85.44 0.00 76.64 79 8 1 0.04 1.62 3.38 0.04 0.08 99.84
76 8 7 1.98 1.62 3.38 12.58 0.00 85.44 0.00 76.64 80 8 7 0.01 1.62 3.38 0.06
77 9 3 0.36 1.62 3.38 0.71 0.00 98.93 0.00 76.64 81 9 3 0.53 1.62 3.38 0.10 0.20 99.17
78 9 9 0.09 1.62 3.38 0.98 0.00 98.93 0.00 76.64 82 9 9 0.02 1.62 3.38 0.60
79 10 5 0.03 1.62 3.38 0.09 0.00 99.87 0.00 76.64 83 10 5 0.01 1.62 3.38 0.02 0.04 99.92
80 10 11 0.07 1.62 3.38 0.06 0.00 99.87 0.00 76.64 84 10 11 0.02 1.62 3.38 0.02
81.fi 85.fi
82.SH SUMMARY EXAMPLE 86.SH SUMMARY EXAMPLE
83The "-s" option prints the column headers just once, 87The "-s" option prints the column headers just once,
@@ -86,9 +90,10 @@ and then the one line system summary for each sample interval.
86.nf 90.nf
87[root@x980]# ./turbostat -s 91[root@x980]# ./turbostat -s
88 %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 92 %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
89 0.61 1.89 3.38 5.95 0.00 93.44 0.00 66.33 93 0.23 1.67 3.38 2.00 0.30 97.47 1.07 82.12
90 0.52 1.62 3.38 6.83 0.00 92.65 0.00 61.11 94 0.10 1.62 3.38 1.87 2.25 95.77 12.02 72.60
91 0.62 1.92 3.38 5.47 0.00 93.91 0.00 67.31 95 0.20 1.64 3.38 1.98 0.11 97.72 0.30 83.36
96 0.11 1.70 3.38 1.86 1.81 96.22 9.71 74.90
92.fi 97.fi
93.SH VERBOSE EXAMPLE 98.SH VERBOSE EXAMPLE
94The "-v" option adds verbosity to the output: 99The "-v" option adds verbosity to the output:
@@ -120,30 +125,28 @@ until ^C while the other CPUs are mostly idle:
120[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null 125[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
121^C 126^C
122cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 127cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
123 8.63 3.64 3.38 14.46 0.49 76.42 0.00 0.00 128 8.86 3.61 3.38 15.06 31.19 44.89 0.00 0.00
124 0 0 0.34 3.36 3.38 99.66 0.00 0.00 0.00 0.00 129 0 0 1.46 3.22 3.38 16.84 29.48 52.22 0.00 0.00
125 0 6 99.96 3.64 3.38 0.04 0.00 0.00 0.00 0.00 130 0 6 0.21 3.06 3.38 18.09
126 1 2 0.14 3.50 3.38 1.75 2.04 96.07 0.00 0.00 131 1 2 0.53 3.33 3.38 2.80 46.40 50.27
127 1 8 0.38 3.57 3.38 1.51 2.04 96.07 0.00 0.00 132 1 8 0.89 3.47 3.38 2.44
128 2 4 0.01 2.65 3.38 0.06 0.00 99.93 0.00 0.00 133 2 4 1.36 3.43 3.38 9.04 23.71 65.89
129 2 10 0.03 2.12 3.38 0.04 0.00 99.93 0.00 0.00 134 2 10 0.18 2.86 3.38 10.22
130 8 1 0.91 3.59 3.38 35.27 0.92 62.90 0.00 0.00 135 8 1 0.04 2.87 3.38 99.96 0.01 0.00
131 8 7 1.61 3.63 3.38 34.57 0.92 62.90 0.00 0.00 136 8 7 99.72 3.63 3.38 0.27
132 9 3 0.04 3.38 3.38 0.20 0.00 99.76 0.00 0.00 137 9 3 0.31 3.21 3.38 7.64 56.55 35.50
133 9 9 0.04 3.29 3.38 0.20 0.00 99.76 0.00 0.00 138 9 9 0.08 2.95 3.38 7.88
134 10 5 0.03 3.08 3.38 0.12 0.00 99.85 0.00 0.00 139 10 5 1.42 3.43 3.38 2.14 30.99 65.44
135 10 11 0.05 3.07 3.38 0.10 0.00 99.85 0.00 0.00 140 10 11 0.16 2.88 3.38 3.40
1364.907015 sec
137
138.fi 141.fi
139Above the cycle soaker drives cpu6 up 3.6 Ghz turbo limit 142Above the cycle soaker drives cpu7 up its 3.6 Ghz turbo limit
140while the other processors are generally in various states of idle. 143while the other processors are generally in various states of idle.
141 144
142Note that cpu0 is an HT sibling sharing core0 145Note that cpu1 and cpu7 are HT siblings within core8.
143with cpu6, and thus it is unable to get to an idle state 146As cpu7 is very busy, it prevents its sibling, cpu1,
144deeper than c1 while cpu6 is busy. 147from entering a c-state deeper than c1.
145 148
146Note that turbostat reports average GHz of 3.64, while 149Note that turbostat reports average GHz of 3.63, while
147the arithmetic average of the GHz column above is lower. 150the arithmetic average of the GHz column above is lower.
148This is a weighted average, where the weight is %c0. ie. it is the total number of 151This is a weighted average, where the weight is %c0. ie. it is the total number of
149un-halted cycles elapsed per time divided by the number of CPUs. 152un-halted cycles elapsed per time divided by the number of CPUs.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 16de7ad4850f..861d77190206 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -67,92 +67,119 @@ double bclk;
67unsigned int show_pkg; 67unsigned int show_pkg;
68unsigned int show_core; 68unsigned int show_core;
69unsigned int show_cpu; 69unsigned int show_cpu;
70unsigned int show_pkg_only;
71unsigned int show_core_only;
72char *output_buffer, *outp;
70 73
71int aperf_mperf_unstable; 74int aperf_mperf_unstable;
72int backwards_count; 75int backwards_count;
73char *progname; 76char *progname;
74 77
75int num_cpus; 78cpu_set_t *cpu_present_set, *cpu_affinity_set;
76cpu_set_t *cpu_present_set, *cpu_mask; 79size_t cpu_present_setsize, cpu_affinity_setsize;
77size_t cpu_present_setsize, cpu_mask_size; 80
78 81struct thread_data {
79struct counters { 82 unsigned long long tsc;
80 unsigned long long tsc; /* per thread */ 83 unsigned long long aperf;
81 unsigned long long aperf; /* per thread */ 84 unsigned long long mperf;
82 unsigned long long mperf; /* per thread */ 85 unsigned long long c1; /* derived */
83 unsigned long long c1; /* per thread (calculated) */ 86 unsigned long long extra_msr;
84 unsigned long long c3; /* per core */ 87 unsigned int cpu_id;
85 unsigned long long c6; /* per core */ 88 unsigned int flags;
86 unsigned long long c7; /* per core */ 89#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
87 unsigned long long pc2; /* per package */ 90#define CPU_IS_FIRST_CORE_IN_PACKAGE 0x4
88 unsigned long long pc3; /* per package */ 91} *thread_even, *thread_odd;
89 unsigned long long pc6; /* per package */ 92
90 unsigned long long pc7; /* per package */ 93struct core_data {
91 unsigned long long extra_msr; /* per thread */ 94 unsigned long long c3;
92 int pkg; 95 unsigned long long c6;
93 int core; 96 unsigned long long c7;
94 int cpu; 97 unsigned int core_id;
95 struct counters *next; 98} *core_even, *core_odd;
96}; 99
97 100struct pkg_data {
98struct counters *cnt_even; 101 unsigned long long pc2;
99struct counters *cnt_odd; 102 unsigned long long pc3;
100struct counters *cnt_delta; 103 unsigned long long pc6;
101struct counters *cnt_average; 104 unsigned long long pc7;
102struct timeval tv_even; 105 unsigned int package_id;
103struct timeval tv_odd; 106} *package_even, *package_odd;
104struct timeval tv_delta; 107
105 108#define ODD_COUNTERS thread_odd, core_odd, package_odd
106int mark_cpu_present(int pkg, int core, int cpu) 109#define EVEN_COUNTERS thread_even, core_even, package_even
110
111#define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
112 (thread_base + (pkg_no) * topo.num_cores_per_pkg * \
113 topo.num_threads_per_core + \
114 (core_no) * topo.num_threads_per_core + (thread_no))
115#define GET_CORE(core_base, core_no, pkg_no) \
116 (core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
117#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
118
119struct system_summary {
120 struct thread_data threads;
121 struct core_data cores;
122 struct pkg_data packages;
123} sum, average;
124
125
126struct topo_params {
127 int num_packages;
128 int num_cpus;
129 int num_cores;
130 int max_cpu_num;
131 int num_cores_per_pkg;
132 int num_threads_per_core;
133} topo;
134
135struct timeval tv_even, tv_odd, tv_delta;
136
137void setup_all_buffers(void);
138
139int cpu_is_not_present(int cpu)
107{ 140{
108 CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set); 141 return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
109 return 0;
110} 142}
111
112/* 143/*
113 * cpu_mask_init(ncpus) 144 * run func(thread, core, package) in topology order
114 * 145 * skip non-present cpus
115 * allocate and clear cpu_mask
116 * set cpu_mask_size
117 */ 146 */
118void cpu_mask_init(int ncpus) 147
148int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
149 struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
119{ 150{
120 cpu_mask = CPU_ALLOC(ncpus); 151 int retval, pkg_no, core_no, thread_no;
121 if (cpu_mask == NULL) {
122 perror("CPU_ALLOC");
123 exit(3);
124 }
125 cpu_mask_size = CPU_ALLOC_SIZE(ncpus);
126 CPU_ZERO_S(cpu_mask_size, cpu_mask);
127 152
128 /* 153 for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
129 * Allocate and initialize cpu_present_set 154 for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
130 */ 155 for (thread_no = 0; thread_no <
131 cpu_present_set = CPU_ALLOC(ncpus); 156 topo.num_threads_per_core; ++thread_no) {
132 if (cpu_present_set == NULL) { 157 struct thread_data *t;
133 perror("CPU_ALLOC"); 158 struct core_data *c;
134 exit(3); 159 struct pkg_data *p;
135 }
136 cpu_present_setsize = CPU_ALLOC_SIZE(ncpus);
137 CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
138 for_all_cpus(mark_cpu_present);
139}
140 160
141void cpu_mask_uninit() 161 t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
142{ 162
143 CPU_FREE(cpu_mask); 163 if (cpu_is_not_present(t->cpu_id))
144 cpu_mask = NULL; 164 continue;
145 cpu_mask_size = 0; 165
146 CPU_FREE(cpu_present_set); 166 c = GET_CORE(core_base, core_no, pkg_no);
147 cpu_present_set = NULL; 167 p = GET_PKG(pkg_base, pkg_no);
148 cpu_present_setsize = 0; 168
169 retval = func(t, c, p);
170 if (retval)
171 return retval;
172 }
173 }
174 }
175 return 0;
149} 176}
150 177
151int cpu_migrate(int cpu) 178int cpu_migrate(int cpu)
152{ 179{
153 CPU_ZERO_S(cpu_mask_size, cpu_mask); 180 CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
154 CPU_SET_S(cpu, cpu_mask_size, cpu_mask); 181 CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
155 if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1) 182 if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
156 return -1; 183 return -1;
157 else 184 else
158 return 0; 185 return 0;
@@ -181,67 +208,72 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
181void print_header(void) 208void print_header(void)
182{ 209{
183 if (show_pkg) 210 if (show_pkg)
184 fprintf(stderr, "pk"); 211 outp += sprintf(outp, "pk");
185 if (show_pkg) 212 if (show_pkg)
186 fprintf(stderr, " "); 213 outp += sprintf(outp, " ");
187 if (show_core) 214 if (show_core)
188 fprintf(stderr, "cor"); 215 outp += sprintf(outp, "cor");
189 if (show_cpu) 216 if (show_cpu)
190 fprintf(stderr, " CPU"); 217 outp += sprintf(outp, " CPU");
191 if (show_pkg || show_core || show_cpu) 218 if (show_pkg || show_core || show_cpu)
192 fprintf(stderr, " "); 219 outp += sprintf(outp, " ");
193 if (do_nhm_cstates) 220 if (do_nhm_cstates)
194 fprintf(stderr, " %%c0"); 221 outp += sprintf(outp, " %%c0");
195 if (has_aperf) 222 if (has_aperf)
196 fprintf(stderr, " GHz"); 223 outp += sprintf(outp, " GHz");
197 fprintf(stderr, " TSC"); 224 outp += sprintf(outp, " TSC");
198 if (do_nhm_cstates) 225 if (do_nhm_cstates)
199 fprintf(stderr, " %%c1"); 226 outp += sprintf(outp, " %%c1");
200 if (do_nhm_cstates) 227 if (do_nhm_cstates)
201 fprintf(stderr, " %%c3"); 228 outp += sprintf(outp, " %%c3");
202 if (do_nhm_cstates) 229 if (do_nhm_cstates)
203 fprintf(stderr, " %%c6"); 230 outp += sprintf(outp, " %%c6");
204 if (do_snb_cstates) 231 if (do_snb_cstates)
205 fprintf(stderr, " %%c7"); 232 outp += sprintf(outp, " %%c7");
206 if (do_snb_cstates) 233 if (do_snb_cstates)
207 fprintf(stderr, " %%pc2"); 234 outp += sprintf(outp, " %%pc2");
208 if (do_nhm_cstates) 235 if (do_nhm_cstates)
209 fprintf(stderr, " %%pc3"); 236 outp += sprintf(outp, " %%pc3");
210 if (do_nhm_cstates) 237 if (do_nhm_cstates)
211 fprintf(stderr, " %%pc6"); 238 outp += sprintf(outp, " %%pc6");
212 if (do_snb_cstates) 239 if (do_snb_cstates)
213 fprintf(stderr, " %%pc7"); 240 outp += sprintf(outp, " %%pc7");
214 if (extra_msr_offset) 241 if (extra_msr_offset)
215 fprintf(stderr, " MSR 0x%x ", extra_msr_offset); 242 outp += sprintf(outp, " MSR 0x%x ", extra_msr_offset);
216 243
217 putc('\n', stderr); 244 outp += sprintf(outp, "\n");
218} 245}
219 246
220void dump_cnt(struct counters *cnt) 247int dump_counters(struct thread_data *t, struct core_data *c,
248 struct pkg_data *p)
221{ 249{
222 if (!cnt) 250 fprintf(stderr, "t %p, c %p, p %p\n", t, c, p);
223 return; 251
224 if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg); 252 if (t) {
225 if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core); 253 fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags);
226 if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu); 254 fprintf(stderr, "TSC: %016llX\n", t->tsc);
227 if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc); 255 fprintf(stderr, "aperf: %016llX\n", t->aperf);
228 if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3); 256 fprintf(stderr, "mperf: %016llX\n", t->mperf);
229 if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6); 257 fprintf(stderr, "c1: %016llX\n", t->c1);
230 if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7); 258 fprintf(stderr, "msr0x%x: %016llX\n",
231 if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf); 259 extra_msr_offset, t->extra_msr);
232 if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2); 260 }
233 if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
234 if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
235 if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
236 if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
237}
238 261
239void dump_list(struct counters *cnt) 262 if (c) {
240{ 263 fprintf(stderr, "core: %d\n", c->core_id);
241 printf("dump_list 0x%p\n", cnt); 264 fprintf(stderr, "c3: %016llX\n", c->c3);
265 fprintf(stderr, "c6: %016llX\n", c->c6);
266 fprintf(stderr, "c7: %016llX\n", c->c7);
267 }
242 268
243 for (; cnt; cnt = cnt->next) 269 if (p) {
244 dump_cnt(cnt); 270 fprintf(stderr, "package: %d\n", p->package_id);
271 fprintf(stderr, "pc2: %016llX\n", p->pc2);
272 fprintf(stderr, "pc3: %016llX\n", p->pc3);
273 fprintf(stderr, "pc6: %016llX\n", p->pc6);
274 fprintf(stderr, "pc7: %016llX\n", p->pc7);
275 }
276 return 0;
245} 277}
246 278
247/* 279/*
@@ -253,321 +285,389 @@ void dump_list(struct counters *cnt)
253 * TSC: "TSC" 3 columns %3.2 285 * TSC: "TSC" 3 columns %3.2
254 * percentage " %pc3" %6.2 286 * percentage " %pc3" %6.2
255 */ 287 */
256void print_cnt(struct counters *p) 288int format_counters(struct thread_data *t, struct core_data *c,
289 struct pkg_data *p)
257{ 290{
258 double interval_float; 291 double interval_float;
259 292
293 /* if showing only 1st thread in core and this isn't one, bail out */
294 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
295 return 0;
296
297 /* if showing only 1st thread in pkg and this isn't one, bail out */
298 if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
299 return 0;
300
260 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; 301 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
261 302
262 /* topology columns, print blanks on 1st (average) line */ 303 /* topo columns, print blanks on 1st (average) line */
263 if (p == cnt_average) { 304 if (t == &average.threads) {
264 if (show_pkg) 305 if (show_pkg)
265 fprintf(stderr, " "); 306 outp += sprintf(outp, " ");
266 if (show_pkg && show_core) 307 if (show_pkg && show_core)
267 fprintf(stderr, " "); 308 outp += sprintf(outp, " ");
268 if (show_core) 309 if (show_core)
269 fprintf(stderr, " "); 310 outp += sprintf(outp, " ");
270 if (show_cpu) 311 if (show_cpu)
271 fprintf(stderr, " " " "); 312 outp += sprintf(outp, " " " ");
272 } else { 313 } else {
273 if (show_pkg) 314 if (show_pkg) {
274 fprintf(stderr, "%2d", p->pkg); 315 if (p)
316 outp += sprintf(outp, "%2d", p->package_id);
317 else
318 outp += sprintf(outp, " ");
319 }
275 if (show_pkg && show_core) 320 if (show_pkg && show_core)
276 fprintf(stderr, " "); 321 outp += sprintf(outp, " ");
277 if (show_core) 322 if (show_core) {
278 fprintf(stderr, "%3d", p->core); 323 if (c)
324 outp += sprintf(outp, "%3d", c->core_id);
325 else
326 outp += sprintf(outp, " ");
327 }
279 if (show_cpu) 328 if (show_cpu)
280 fprintf(stderr, " %3d", p->cpu); 329 outp += sprintf(outp, " %3d", t->cpu_id);
281 } 330 }
282 331
283 /* %c0 */ 332 /* %c0 */
284 if (do_nhm_cstates) { 333 if (do_nhm_cstates) {
285 if (show_pkg || show_core || show_cpu) 334 if (show_pkg || show_core || show_cpu)
286 fprintf(stderr, " "); 335 outp += sprintf(outp, " ");
287 if (!skip_c0) 336 if (!skip_c0)
288 fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc); 337 outp += sprintf(outp, "%6.2f", 100.0 * t->mperf/t->tsc);
289 else 338 else
290 fprintf(stderr, " ****"); 339 outp += sprintf(outp, " ****");
291 } 340 }
292 341
293 /* GHz */ 342 /* GHz */
294 if (has_aperf) { 343 if (has_aperf) {
295 if (!aperf_mperf_unstable) { 344 if (!aperf_mperf_unstable) {
296 fprintf(stderr, " %3.2f", 345 outp += sprintf(outp, " %3.2f",
297 1.0 * p->tsc / units * p->aperf / 346 1.0 * t->tsc / units * t->aperf /
298 p->mperf / interval_float); 347 t->mperf / interval_float);
299 } else { 348 } else {
300 if (p->aperf > p->tsc || p->mperf > p->tsc) { 349 if (t->aperf > t->tsc || t->mperf > t->tsc) {
301 fprintf(stderr, " ***"); 350 outp += sprintf(outp, " ***");
302 } else { 351 } else {
303 fprintf(stderr, "%3.1f*", 352 outp += sprintf(outp, "%3.1f*",
304 1.0 * p->tsc / 353 1.0 * t->tsc /
305 units * p->aperf / 354 units * t->aperf /
306 p->mperf / interval_float); 355 t->mperf / interval_float);
307 } 356 }
308 } 357 }
309 } 358 }
310 359
311 /* TSC */ 360 /* TSC */
312 fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float); 361 outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
313 362
314 if (do_nhm_cstates) { 363 if (do_nhm_cstates) {
315 if (!skip_c1) 364 if (!skip_c1)
316 fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc); 365 outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc);
317 else 366 else
318 fprintf(stderr, " ****"); 367 outp += sprintf(outp, " ****");
319 } 368 }
369
370 /* print per-core data only for 1st thread in core */
371 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
372 goto done;
373
320 if (do_nhm_cstates) 374 if (do_nhm_cstates)
321 fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc); 375 outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc);
322 if (do_nhm_cstates) 376 if (do_nhm_cstates)
323 fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc); 377 outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc);
324 if (do_snb_cstates) 378 if (do_snb_cstates)
325 fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); 379 outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc);
380
381 /* print per-package data only for 1st core in package */
382 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
383 goto done;
384
326 if (do_snb_cstates) 385 if (do_snb_cstates)
327 fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc); 386 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc);
328 if (do_nhm_cstates) 387 if (do_nhm_cstates)
329 fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc); 388 outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc);
330 if (do_nhm_cstates) 389 if (do_nhm_cstates)
331 fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc); 390 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc);
332 if (do_snb_cstates) 391 if (do_snb_cstates)
333 fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc); 392 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
393done:
334 if (extra_msr_offset) 394 if (extra_msr_offset)
335 fprintf(stderr, " 0x%016llx", p->extra_msr); 395 outp += sprintf(outp, " 0x%016llx", t->extra_msr);
336 putc('\n', stderr); 396 outp += sprintf(outp, "\n");
397
398 return 0;
337} 399}
338 400
339void print_counters(struct counters *counters) 401void flush_stdout()
402{
403 fputs(output_buffer, stdout);
404 outp = output_buffer;
405}
406void flush_stderr()
407{
408 fputs(output_buffer, stderr);
409 outp = output_buffer;
410}
411void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
340{ 412{
341 struct counters *cnt;
342 static int printed; 413 static int printed;
343 414
344
345 if (!printed || !summary_only) 415 if (!printed || !summary_only)
346 print_header(); 416 print_header();
347 417
348 if (num_cpus > 1) 418 if (topo.num_cpus > 1)
349 print_cnt(cnt_average); 419 format_counters(&average.threads, &average.cores,
420 &average.packages);
350 421
351 printed = 1; 422 printed = 1;
352 423
353 if (summary_only) 424 if (summary_only)
354 return; 425 return;
355 426
356 for (cnt = counters; cnt != NULL; cnt = cnt->next) 427 for_all_cpus(format_counters, t, c, p);
357 print_cnt(cnt);
358
359} 428}
360 429
361#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after)) 430void
431delta_package(struct pkg_data *new, struct pkg_data *old)
432{
433 old->pc2 = new->pc2 - old->pc2;
434 old->pc3 = new->pc3 - old->pc3;
435 old->pc6 = new->pc6 - old->pc6;
436 old->pc7 = new->pc7 - old->pc7;
437}
362 438
363int compute_delta(struct counters *after, 439void
364 struct counters *before, struct counters *delta) 440delta_core(struct core_data *new, struct core_data *old)
365{ 441{
366 int errors = 0; 442 old->c3 = new->c3 - old->c3;
367 int perf_err = 0; 443 old->c6 = new->c6 - old->c6;
444 old->c7 = new->c7 - old->c7;
445}
368 446
369 skip_c0 = skip_c1 = 0; 447/*
448 * old = new - old
449 */
450void
451delta_thread(struct thread_data *new, struct thread_data *old,
452 struct core_data *core_delta)
453{
454 old->tsc = new->tsc - old->tsc;
455
456 /* check for TSC < 1 Mcycles over interval */
457 if (old->tsc < (1000 * 1000)) {
458 fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n");
459 fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n");
460 fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n");
461 exit(-3);
462 }
370 463
371 for ( ; after && before && delta; 464 old->c1 = new->c1 - old->c1;
372 after = after->next, before = before->next, delta = delta->next) {
373 if (before->cpu != after->cpu) {
374 printf("cpu configuration changed: %d != %d\n",
375 before->cpu, after->cpu);
376 return -1;
377 }
378 465
379 if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) { 466 if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
380 fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n", 467 old->aperf = new->aperf - old->aperf;
381 before->cpu, before->tsc, after->tsc); 468 old->mperf = new->mperf - old->mperf;
382 errors++; 469 } else {
383 }
384 /* check for TSC < 1 Mcycles over interval */
385 if (delta->tsc < (1000 * 1000)) {
386 fprintf(stderr, "Insanely slow TSC rate,"
387 " TSC stops in idle?\n");
388 fprintf(stderr, "You can disable all c-states"
389 " by booting with \"idle=poll\"\n");
390 fprintf(stderr, "or just the deep ones with"
391 " \"processor.max_cstate=1\"\n");
392 exit(-3);
393 }
394 if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
395 fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
396 before->cpu, before->c3, after->c3);
397 errors++;
398 }
399 if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
400 fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
401 before->cpu, before->c6, after->c6);
402 errors++;
403 }
404 if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
405 fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
406 before->cpu, before->c7, after->c7);
407 errors++;
408 }
409 if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
410 fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
411 before->cpu, before->pc2, after->pc2);
412 errors++;
413 }
414 if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
415 fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
416 before->cpu, before->pc3, after->pc3);
417 errors++;
418 }
419 if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
420 fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
421 before->cpu, before->pc6, after->pc6);
422 errors++;
423 }
424 if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
425 fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
426 before->cpu, before->pc7, after->pc7);
427 errors++;
428 }
429 470
430 perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf); 471 if (!aperf_mperf_unstable) {
431 if (perf_err) { 472 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
432 fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n", 473 fprintf(stderr, "* Frequency results do not cover entire interval *\n");
433 before->cpu, before->aperf, after->aperf); 474 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
434 }
435 perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
436 if (perf_err) {
437 fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
438 before->cpu, before->mperf, after->mperf);
439 }
440 if (perf_err) {
441 if (!aperf_mperf_unstable) {
442 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
443 fprintf(stderr, "* Frequency results do not cover entire interval *\n");
444 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
445 475
446 aperf_mperf_unstable = 1; 476 aperf_mperf_unstable = 1;
447 }
448 /*
449 * mperf delta is likely a huge "positive" number
450 * can not use it for calculating c0 time
451 */
452 skip_c0 = 1;
453 skip_c1 = 1;
454 } 477 }
455
456 /* 478 /*
457 * As mperf and tsc collection are not atomic, 479 * mperf delta is likely a huge "positive" number
458 * it is possible for mperf's non-halted cycles 480 * can not use it for calculating c0 time
459 * to exceed TSC's all cycles: show c1 = 0% in that case.
460 */ 481 */
461 if (delta->mperf > delta->tsc) 482 skip_c0 = 1;
462 delta->c1 = 0; 483 skip_c1 = 1;
463 else /* normal case, derive c1 */ 484 }
464 delta->c1 = delta->tsc - delta->mperf
465 - delta->c3 - delta->c6 - delta->c7;
466 485
467 if (delta->mperf == 0)
468 delta->mperf = 1; /* divide by 0 protection */
469 486
470 /* 487 /*
471 * for "extra msr", just copy the latest w/o subtracting 488 * As counter collection is not atomic,
472 */ 489 * it is possible for mperf's non-halted cycles + idle states
473 delta->extra_msr = after->extra_msr; 490 * to exceed TSC's all cycles: show c1 = 0% in that case.
474 if (errors) { 491 */
475 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu); 492 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc)
476 dump_cnt(before); 493 old->c1 = 0;
477 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu); 494 else {
478 dump_cnt(after); 495 /* normal case, derive c1 */
479 errors = 0; 496 old->c1 = old->tsc - old->mperf - core_delta->c3
480 } 497 - core_delta->c6 - core_delta->c7;
481 } 498 }
499
500 if (old->mperf == 0) {
501 if (verbose > 1) fprintf(stderr, "cpu%d MPERF 0!\n", old->cpu_id);
502 old->mperf = 1; /* divide by 0 protection */
503 }
504
505 /*
506 * for "extra msr", just copy the latest w/o subtracting
507 */
508 old->extra_msr = new->extra_msr;
509}
510
511int delta_cpu(struct thread_data *t, struct core_data *c,
512 struct pkg_data *p, struct thread_data *t2,
513 struct core_data *c2, struct pkg_data *p2)
514{
515 /* calculate core delta only for 1st thread in core */
516 if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE)
517 delta_core(c, c2);
518
519 /* always calculate thread delta */
520 delta_thread(t, t2, c2); /* c2 is core delta */
521
522 /* calculate package delta only for 1st core in package */
523 if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)
524 delta_package(p, p2);
525
482 return 0; 526 return 0;
483} 527}
484 528
485void compute_average(struct counters *delta, struct counters *avg) 529void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
530{
531 t->tsc = 0;
532 t->aperf = 0;
533 t->mperf = 0;
534 t->c1 = 0;
535
536 /* tells format_counters to dump all fields from this set */
537 t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
538
539 c->c3 = 0;
540 c->c6 = 0;
541 c->c7 = 0;
542
543 p->pc2 = 0;
544 p->pc3 = 0;
545 p->pc6 = 0;
546 p->pc7 = 0;
547}
548int sum_counters(struct thread_data *t, struct core_data *c,
549 struct pkg_data *p)
486{ 550{
487 struct counters *sum; 551 average.threads.tsc += t->tsc;
552 average.threads.aperf += t->aperf;
553 average.threads.mperf += t->mperf;
554 average.threads.c1 += t->c1;
488 555
489 sum = calloc(1, sizeof(struct counters)); 556 /* sum per-core values only for 1st thread in core */
490 if (sum == NULL) { 557 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
491 perror("calloc sum"); 558 return 0;
492 exit(1);
493 }
494 559
495 for (; delta; delta = delta->next) { 560 average.cores.c3 += c->c3;
496 sum->tsc += delta->tsc; 561 average.cores.c6 += c->c6;
497 sum->c1 += delta->c1; 562 average.cores.c7 += c->c7;
498 sum->c3 += delta->c3; 563
499 sum->c6 += delta->c6; 564 /* sum per-pkg values only for 1st core in pkg */
500 sum->c7 += delta->c7; 565 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
501 sum->aperf += delta->aperf; 566 return 0;
502 sum->mperf += delta->mperf; 567
503 sum->pc2 += delta->pc2; 568 average.packages.pc2 += p->pc2;
504 sum->pc3 += delta->pc3; 569 average.packages.pc3 += p->pc3;
505 sum->pc6 += delta->pc6; 570 average.packages.pc6 += p->pc6;
506 sum->pc7 += delta->pc7; 571 average.packages.pc7 += p->pc7;
507 } 572
508 avg->tsc = sum->tsc/num_cpus; 573 return 0;
509 avg->c1 = sum->c1/num_cpus; 574}
510 avg->c3 = sum->c3/num_cpus; 575/*
511 avg->c6 = sum->c6/num_cpus; 576 * sum the counters for all cpus in the system
512 avg->c7 = sum->c7/num_cpus; 577 * compute the weighted average
513 avg->aperf = sum->aperf/num_cpus; 578 */
514 avg->mperf = sum->mperf/num_cpus; 579void compute_average(struct thread_data *t, struct core_data *c,
515 avg->pc2 = sum->pc2/num_cpus; 580 struct pkg_data *p)
516 avg->pc3 = sum->pc3/num_cpus; 581{
517 avg->pc6 = sum->pc6/num_cpus; 582 clear_counters(&average.threads, &average.cores, &average.packages);
518 avg->pc7 = sum->pc7/num_cpus; 583
519 584 for_all_cpus(sum_counters, t, c, p);
520 free(sum); 585
586 average.threads.tsc /= topo.num_cpus;
587 average.threads.aperf /= topo.num_cpus;
588 average.threads.mperf /= topo.num_cpus;
589 average.threads.c1 /= topo.num_cpus;
590
591 average.cores.c3 /= topo.num_cores;
592 average.cores.c6 /= topo.num_cores;
593 average.cores.c7 /= topo.num_cores;
594
595 average.packages.pc2 /= topo.num_packages;
596 average.packages.pc3 /= topo.num_packages;
597 average.packages.pc6 /= topo.num_packages;
598 average.packages.pc7 /= topo.num_packages;
521} 599}
522 600
523int get_counters(struct counters *cnt) 601static unsigned long long rdtsc(void)
524{ 602{
525 for ( ; cnt; cnt = cnt->next) { 603 unsigned int low, high;
526 604
527 if (cpu_migrate(cnt->cpu)) 605 asm volatile("rdtsc" : "=a" (low), "=d" (high));
528 return -1;
529 606
530 if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc)) 607 return low | ((unsigned long long)high) << 32;
531 return -1; 608}
532 609
533 if (has_aperf) {
534 if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf))
535 return -1;
536 if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf))
537 return -1;
538 }
539 610
540 if (do_nhm_cstates) { 611/*
541 if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3)) 612 * get_counters(...)
542 return -1; 613 * migrate to cpu
543 if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6)) 614 * acquire and record local counters for that cpu
544 return -1; 615 */
545 } 616int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
617{
618 int cpu = t->cpu_id;
546 619
547 if (do_snb_cstates) 620 if (cpu_migrate(cpu))
548 if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7)) 621 return -1;
549 return -1;
550 622
551 if (do_nhm_cstates) { 623 t->tsc = rdtsc(); /* we are running on local CPU of interest */
552 if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3)) 624
553 return -1; 625 if (has_aperf) {
554 if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6)) 626 if (get_msr(cpu, MSR_APERF, &t->aperf))
555 return -1; 627 return -3;
556 } 628 if (get_msr(cpu, MSR_MPERF, &t->mperf))
557 if (do_snb_cstates) { 629 return -4;
558 if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2)) 630 }
559 return -1; 631
560 if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7)) 632 if (extra_msr_offset)
561 return -1; 633 if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
562 } 634 return -5;
563 if (extra_msr_offset) 635
564 if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr)) 636 /* collect core counters only for 1st thread in core */
565 return -1; 637 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
638 return 0;
639
640 if (do_nhm_cstates) {
641 if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
642 return -6;
643 if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
644 return -7;
645 }
646
647 if (do_snb_cstates)
648 if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
649 return -8;
650
651 /* collect package counters only for 1st core in package */
652 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
653 return 0;
654
655 if (do_nhm_cstates) {
656 if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
657 return -9;
658 if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
659 return -10;
660 }
661 if (do_snb_cstates) {
662 if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2))
663 return -11;
664 if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
665 return -12;
566 } 666 }
567 return 0; 667 return 0;
568} 668}
569 669
570void print_nehalem_info(void) 670void print_verbose_header(void)
571{ 671{
572 unsigned long long msr; 672 unsigned long long msr;
573 unsigned int ratio; 673 unsigned int ratio;
@@ -615,143 +715,82 @@ void print_nehalem_info(void)
615 715
616} 716}
617 717
618void free_counter_list(struct counters *list) 718void free_all_buffers(void)
619{ 719{
620 struct counters *p; 720 CPU_FREE(cpu_present_set);
721 cpu_present_set = NULL;
722 cpu_present_set = 0;
621 723
622 for (p = list; p; ) { 724 CPU_FREE(cpu_affinity_set);
623 struct counters *free_me; 725 cpu_affinity_set = NULL;
726 cpu_affinity_setsize = 0;
624 727
625 free_me = p; 728 free(thread_even);
626 p = p->next; 729 free(core_even);
627 free(free_me); 730 free(package_even);
628 }
629}
630 731
631void free_all_counters(void) 732 thread_even = NULL;
632{ 733 core_even = NULL;
633 free_counter_list(cnt_even); 734 package_even = NULL;
634 cnt_even = NULL;
635 735
636 free_counter_list(cnt_odd); 736 free(thread_odd);
637 cnt_odd = NULL; 737 free(core_odd);
738 free(package_odd);
638 739
639 free_counter_list(cnt_delta); 740 thread_odd = NULL;
640 cnt_delta = NULL; 741 core_odd = NULL;
742 package_odd = NULL;
641 743
642 free_counter_list(cnt_average); 744 free(output_buffer);
643 cnt_average = NULL; 745 output_buffer = NULL;
746 outp = NULL;
644} 747}
645 748
646void insert_counters(struct counters **list, 749/*
647 struct counters *new) 750 * cpu_is_first_sibling_in_core(cpu)
751 * return 1 if given CPU is 1st HT sibling in the core
752 */
753int cpu_is_first_sibling_in_core(int cpu)
648{ 754{
649 struct counters *prev; 755 char path[64];
650 756 FILE *filep;
651 /* 757 int first_cpu;
652 * list was empty
653 */
654 if (*list == NULL) {
655 new->next = *list;
656 *list = new;
657 return;
658 }
659
660 if (!summary_only)
661 show_cpu = 1; /* there is more than one CPU */
662
663 /*
664 * insert on front of list.
665 * It is sorted by ascending package#, core#, cpu#
666 */
667 if (((*list)->pkg > new->pkg) ||
668 (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
669 (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
670 new->next = *list;
671 *list = new;
672 return;
673 }
674
675 prev = *list;
676
677 while (prev->next && (prev->next->pkg < new->pkg)) {
678 prev = prev->next;
679 if (!summary_only)
680 show_pkg = 1; /* there is more than 1 package */
681 }
682
683 while (prev->next && (prev->next->pkg == new->pkg)
684 && (prev->next->core < new->core)) {
685 prev = prev->next;
686 if (!summary_only)
687 show_core = 1; /* there is more than 1 core */
688 }
689 758
690 while (prev->next && (prev->next->pkg == new->pkg) 759 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
691 && (prev->next->core == new->core) 760 filep = fopen(path, "r");
692 && (prev->next->cpu < new->cpu)) { 761 if (filep == NULL) {
693 prev = prev->next; 762 perror(path);
763 exit(1);
694 } 764 }
695 765 fscanf(filep, "%d", &first_cpu);
696 /* 766 fclose(filep);
697 * insert after "prev" 767 return (cpu == first_cpu);
698 */
699 new->next = prev->next;
700 prev->next = new;
701} 768}
702 769
703void alloc_new_counters(int pkg, int core, int cpu) 770/*
771 * cpu_is_first_core_in_package(cpu)
772 * return 1 if given CPU is 1st core in package
773 */
774int cpu_is_first_core_in_package(int cpu)
704{ 775{
705 struct counters *new; 776 char path[64];
706 777 FILE *filep;
707 if (verbose > 1) 778 int first_cpu;
708 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
709
710 new = (struct counters *)calloc(1, sizeof(struct counters));
711 if (new == NULL) {
712 perror("calloc");
713 exit(1);
714 }
715 new->pkg = pkg;
716 new->core = core;
717 new->cpu = cpu;
718 insert_counters(&cnt_odd, new);
719
720 new = (struct counters *)calloc(1,
721 sizeof(struct counters));
722 if (new == NULL) {
723 perror("calloc");
724 exit(1);
725 }
726 new->pkg = pkg;
727 new->core = core;
728 new->cpu = cpu;
729 insert_counters(&cnt_even, new);
730
731 new = (struct counters *)calloc(1, sizeof(struct counters));
732 if (new == NULL) {
733 perror("calloc");
734 exit(1);
735 }
736 new->pkg = pkg;
737 new->core = core;
738 new->cpu = cpu;
739 insert_counters(&cnt_delta, new);
740 779
741 new = (struct counters *)calloc(1, sizeof(struct counters)); 780 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);
742 if (new == NULL) { 781 filep = fopen(path, "r");
743 perror("calloc"); 782 if (filep == NULL) {
783 perror(path);
744 exit(1); 784 exit(1);
745 } 785 }
746 new->pkg = pkg; 786 fscanf(filep, "%d", &first_cpu);
747 new->core = core; 787 fclose(filep);
748 new->cpu = cpu; 788 return (cpu == first_cpu);
749 cnt_average = new;
750} 789}
751 790
752int get_physical_package_id(int cpu) 791int get_physical_package_id(int cpu)
753{ 792{
754 char path[64]; 793 char path[80];
755 FILE *filep; 794 FILE *filep;
756 int pkg; 795 int pkg;
757 796
@@ -768,7 +807,7 @@ int get_physical_package_id(int cpu)
768 807
769int get_core_id(int cpu) 808int get_core_id(int cpu)
770{ 809{
771 char path[64]; 810 char path[80];
772 FILE *filep; 811 FILE *filep;
773 int core; 812 int core;
774 813
@@ -783,14 +822,87 @@ int get_core_id(int cpu)
783 return core; 822 return core;
784} 823}
785 824
825int get_num_ht_siblings(int cpu)
826{
827 char path[80];
828 FILE *filep;
829 int sib1, sib2;
830 int matches;
831 char character;
832
833 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
834 filep = fopen(path, "r");
835 if (filep == NULL) {
836 perror(path);
837 exit(1);
838 }
839 /*
840 * file format:
841 * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4)
842 * otherwinse 1 sibling (self).
843 */
844 matches = fscanf(filep, "%d%c%d\n", &sib1, &character, &sib2);
845
846 fclose(filep);
847
848 if (matches == 3)
849 return 2;
850 else
851 return 1;
852}
853
786/* 854/*
787 * run func(pkg, core, cpu) on every cpu in /proc/stat 855 * run func(thread, core, package) in topology order
856 * skip non-present cpus
788 */ 857 */
789 858
790int for_all_cpus(void (func)(int, int, int)) 859int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *,
860 struct pkg_data *, struct thread_data *, struct core_data *,
861 struct pkg_data *), struct thread_data *thread_base,
862 struct core_data *core_base, struct pkg_data *pkg_base,
863 struct thread_data *thread_base2, struct core_data *core_base2,
864 struct pkg_data *pkg_base2)
865{
866 int retval, pkg_no, core_no, thread_no;
867
868 for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
869 for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
870 for (thread_no = 0; thread_no <
871 topo.num_threads_per_core; ++thread_no) {
872 struct thread_data *t, *t2;
873 struct core_data *c, *c2;
874 struct pkg_data *p, *p2;
875
876 t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
877
878 if (cpu_is_not_present(t->cpu_id))
879 continue;
880
881 t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no);
882
883 c = GET_CORE(core_base, core_no, pkg_no);
884 c2 = GET_CORE(core_base2, core_no, pkg_no);
885
886 p = GET_PKG(pkg_base, pkg_no);
887 p2 = GET_PKG(pkg_base2, pkg_no);
888
889 retval = func(t, c, p, t2, c2, p2);
890 if (retval)
891 return retval;
892 }
893 }
894 }
895 return 0;
896}
897
898/*
899 * run func(cpu) on every cpu in /proc/stat
900 * return max_cpu number
901 */
902int for_all_proc_cpus(int (func)(int))
791{ 903{
792 FILE *fp; 904 FILE *fp;
793 int cpu_count; 905 int cpu_num;
794 int retval; 906 int retval;
795 907
796 fp = fopen(proc_stat, "r"); 908 fp = fopen(proc_stat, "r");
@@ -805,78 +917,88 @@ int for_all_cpus(void (func)(int, int, int))
805 exit(1); 917 exit(1);
806 } 918 }
807 919
808 for (cpu_count = 0; ; cpu_count++) { 920 while (1) {
809 int cpu; 921 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num);
810
811 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
812 if (retval != 1) 922 if (retval != 1)
813 break; 923 break;
814 924
815 func(get_physical_package_id(cpu), get_core_id(cpu), cpu); 925 retval = func(cpu_num);
926 if (retval) {
927 fclose(fp);
928 return(retval);
929 }
816 } 930 }
817 fclose(fp); 931 fclose(fp);
818 return cpu_count; 932 return 0;
819} 933}
820 934
821void re_initialize(void) 935void re_initialize(void)
822{ 936{
823 free_all_counters(); 937 free_all_buffers();
824 num_cpus = for_all_cpus(alloc_new_counters); 938 setup_all_buffers();
825 cpu_mask_uninit(); 939 printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus);
826 cpu_mask_init(num_cpus);
827 printf("turbostat: re-initialized with num_cpus %d\n", num_cpus);
828} 940}
829 941
830void dummy(int pkg, int core, int cpu) { return; } 942
831/* 943/*
832 * check to see if a cpu came on-line 944 * count_cpus()
945 * remember the last one seen, it will be the max
833 */ 946 */
834int verify_num_cpus(void) 947int count_cpus(int cpu)
835{ 948{
836 int new_num_cpus; 949 if (topo.max_cpu_num < cpu)
837 950 topo.max_cpu_num = cpu;
838 new_num_cpus = for_all_cpus(dummy);
839 951
840 if (new_num_cpus != num_cpus) { 952 topo.num_cpus += 1;
841 if (verbose) 953 return 0;
842 printf("num_cpus was %d, is now %d\n", 954}
843 num_cpus, new_num_cpus); 955int mark_cpu_present(int cpu)
844 return -1; 956{
845 } 957 CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set);
846 return 0; 958 return 0;
847} 959}
848 960
849void turbostat_loop() 961void turbostat_loop()
850{ 962{
963 int retval;
964
851restart: 965restart:
852 get_counters(cnt_even); 966 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
967 if (retval) {
968 re_initialize();
969 goto restart;
970 }
853 gettimeofday(&tv_even, (struct timezone *)NULL); 971 gettimeofday(&tv_even, (struct timezone *)NULL);
854 972
855 while (1) { 973 while (1) {
856 if (verify_num_cpus()) { 974 if (for_all_proc_cpus(cpu_is_not_present)) {
857 re_initialize(); 975 re_initialize();
858 goto restart; 976 goto restart;
859 } 977 }
860 sleep(interval_sec); 978 sleep(interval_sec);
861 if (get_counters(cnt_odd)) { 979 retval = for_all_cpus(get_counters, ODD_COUNTERS);
980 if (retval) {
862 re_initialize(); 981 re_initialize();
863 goto restart; 982 goto restart;
864 } 983 }
865 gettimeofday(&tv_odd, (struct timezone *)NULL); 984 gettimeofday(&tv_odd, (struct timezone *)NULL);
866 compute_delta(cnt_odd, cnt_even, cnt_delta);
867 timersub(&tv_odd, &tv_even, &tv_delta); 985 timersub(&tv_odd, &tv_even, &tv_delta);
868 compute_average(cnt_delta, cnt_average); 986 for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
869 print_counters(cnt_delta); 987 compute_average(EVEN_COUNTERS);
988 format_all_counters(EVEN_COUNTERS);
989 flush_stdout();
870 sleep(interval_sec); 990 sleep(interval_sec);
871 if (get_counters(cnt_even)) { 991 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
992 if (retval) {
872 re_initialize(); 993 re_initialize();
873 goto restart; 994 goto restart;
874 } 995 }
875 gettimeofday(&tv_even, (struct timezone *)NULL); 996 gettimeofday(&tv_even, (struct timezone *)NULL);
876 compute_delta(cnt_even, cnt_odd, cnt_delta);
877 timersub(&tv_even, &tv_odd, &tv_delta); 997 timersub(&tv_even, &tv_odd, &tv_delta);
878 compute_average(cnt_delta, cnt_average); 998 for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS);
879 print_counters(cnt_delta); 999 compute_average(ODD_COUNTERS);
1000 format_all_counters(ODD_COUNTERS);
1001 flush_stdout();
880 } 1002 }
881} 1003}
882 1004
@@ -1051,6 +1173,208 @@ int open_dev_cpu_msr(int dummy1)
1051 return 0; 1173 return 0;
1052} 1174}
1053 1175
1176void topology_probe()
1177{
1178 int i;
1179 int max_core_id = 0;
1180 int max_package_id = 0;
1181 int max_siblings = 0;
1182 struct cpu_topology {
1183 int core_id;
1184 int physical_package_id;
1185 } *cpus;
1186
1187 /* Initialize num_cpus, max_cpu_num */
1188 topo.num_cpus = 0;
1189 topo.max_cpu_num = 0;
1190 for_all_proc_cpus(count_cpus);
1191 if (!summary_only && topo.num_cpus > 1)
1192 show_cpu = 1;
1193
1194 if (verbose > 1)
1195 fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
1196
1197 cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology));
1198 if (cpus == NULL) {
1199 perror("calloc cpus");
1200 exit(1);
1201 }
1202
1203 /*
1204 * Allocate and initialize cpu_present_set
1205 */
1206 cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1));
1207 if (cpu_present_set == NULL) {
1208 perror("CPU_ALLOC");
1209 exit(3);
1210 }
1211 cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
1212 CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
1213 for_all_proc_cpus(mark_cpu_present);
1214
1215 /*
1216 * Allocate and initialize cpu_affinity_set
1217 */
1218 cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1));
1219 if (cpu_affinity_set == NULL) {
1220 perror("CPU_ALLOC");
1221 exit(3);
1222 }
1223 cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
1224 CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
1225
1226
1227 /*
1228 * For online cpus
1229 * find max_core_id, max_package_id
1230 */
1231 for (i = 0; i <= topo.max_cpu_num; ++i) {
1232 int siblings;
1233
1234 if (cpu_is_not_present(i)) {
1235 if (verbose > 1)
1236 fprintf(stderr, "cpu%d NOT PRESENT\n", i);
1237 continue;
1238 }
1239 cpus[i].core_id = get_core_id(i);
1240 if (cpus[i].core_id > max_core_id)
1241 max_core_id = cpus[i].core_id;
1242
1243 cpus[i].physical_package_id = get_physical_package_id(i);
1244 if (cpus[i].physical_package_id > max_package_id)
1245 max_package_id = cpus[i].physical_package_id;
1246
1247 siblings = get_num_ht_siblings(i);
1248 if (siblings > max_siblings)
1249 max_siblings = siblings;
1250 if (verbose > 1)
1251 fprintf(stderr, "cpu %d pkg %d core %d\n",
1252 i, cpus[i].physical_package_id, cpus[i].core_id);
1253 }
1254 topo.num_cores_per_pkg = max_core_id + 1;
1255 if (verbose > 1)
1256 fprintf(stderr, "max_core_id %d, sizing for %d cores per package\n",
1257 max_core_id, topo.num_cores_per_pkg);
1258 if (!summary_only && topo.num_cores_per_pkg > 1)
1259 show_core = 1;
1260
1261 topo.num_packages = max_package_id + 1;
1262 if (verbose > 1)
1263 fprintf(stderr, "max_package_id %d, sizing for %d packages\n",
1264 max_package_id, topo.num_packages);
1265 if (!summary_only && topo.num_packages > 1)
1266 show_pkg = 1;
1267
1268 topo.num_threads_per_core = max_siblings;
1269 if (verbose > 1)
1270 fprintf(stderr, "max_siblings %d\n", max_siblings);
1271
1272 free(cpus);
1273}
1274
1275void
1276allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p)
1277{
1278 int i;
1279
1280 *t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
1281 topo.num_packages, sizeof(struct thread_data));
1282 if (*t == NULL)
1283 goto error;
1284
1285 for (i = 0; i < topo.num_threads_per_core *
1286 topo.num_cores_per_pkg * topo.num_packages; i++)
1287 (*t)[i].cpu_id = -1;
1288
1289 *c = calloc(topo.num_cores_per_pkg * topo.num_packages,
1290 sizeof(struct core_data));
1291 if (*c == NULL)
1292 goto error;
1293
1294 for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
1295 (*c)[i].core_id = -1;
1296
1297 *p = calloc(topo.num_packages, sizeof(struct pkg_data));
1298 if (*p == NULL)
1299 goto error;
1300
1301 for (i = 0; i < topo.num_packages; i++)
1302 (*p)[i].package_id = i;
1303
1304 return;
1305error:
1306 perror("calloc counters");
1307 exit(1);
1308}
1309/*
1310 * init_counter()
1311 *
1312 * set cpu_id, core_num, pkg_num
1313 * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE
1314 *
1315 * increment topo.num_cores when 1st core in pkg seen
1316 */
1317void init_counter(struct thread_data *thread_base, struct core_data *core_base,
1318 struct pkg_data *pkg_base, int thread_num, int core_num,
1319 int pkg_num, int cpu_id)
1320{
1321 struct thread_data *t;
1322 struct core_data *c;
1323 struct pkg_data *p;
1324
1325 t = GET_THREAD(thread_base, thread_num, core_num, pkg_num);
1326 c = GET_CORE(core_base, core_num, pkg_num);
1327 p = GET_PKG(pkg_base, pkg_num);
1328
1329 t->cpu_id = cpu_id;
1330 if (thread_num == 0) {
1331 t->flags |= CPU_IS_FIRST_THREAD_IN_CORE;
1332 if (cpu_is_first_core_in_package(cpu_id))
1333 t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE;
1334 }
1335
1336 c->core_id = core_num;
1337 p->package_id = pkg_num;
1338}
1339
1340
1341int initialize_counters(int cpu_id)
1342{
1343 int my_thread_id, my_core_id, my_package_id;
1344
1345 my_package_id = get_physical_package_id(cpu_id);
1346 my_core_id = get_core_id(cpu_id);
1347
1348 if (cpu_is_first_sibling_in_core(cpu_id)) {
1349 my_thread_id = 0;
1350 topo.num_cores++;
1351 } else {
1352 my_thread_id = 1;
1353 }
1354
1355 init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
1356 init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
1357 return 0;
1358}
1359
1360void allocate_output_buffer()
1361{
1362 output_buffer = calloc(1, (1 + topo.num_cpus) * 128);
1363 outp = output_buffer;
1364 if (outp == NULL) {
1365 perror("calloc");
1366 exit(-1);
1367 }
1368}
1369
1370void setup_all_buffers(void)
1371{
1372 topology_probe();
1373 allocate_counters(&thread_even, &core_even, &package_even);
1374 allocate_counters(&thread_odd, &core_odd, &package_odd);
1375 allocate_output_buffer();
1376 for_all_proc_cpus(initialize_counters);
1377}
1054void turbostat_init() 1378void turbostat_init()
1055{ 1379{
1056 check_cpuid(); 1380 check_cpuid();
@@ -1058,21 +1382,19 @@ void turbostat_init()
1058 check_dev_msr(); 1382 check_dev_msr();
1059 check_super_user(); 1383 check_super_user();
1060 1384
1061 num_cpus = for_all_cpus(alloc_new_counters); 1385 setup_all_buffers();
1062 cpu_mask_init(num_cpus);
1063 1386
1064 if (verbose) 1387 if (verbose)
1065 print_nehalem_info(); 1388 print_verbose_header();
1066} 1389}
1067 1390
1068int fork_it(char **argv) 1391int fork_it(char **argv)
1069{ 1392{
1070 int retval;
1071 pid_t child_pid; 1393 pid_t child_pid;
1072 get_counters(cnt_even);
1073 1394
1074 /* clear affinity side-effect of get_counters() */ 1395 for_all_cpus(get_counters, EVEN_COUNTERS);
1075 sched_setaffinity(0, cpu_present_setsize, cpu_present_set); 1396 /* clear affinity side-effect of get_counters() */
1397 sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
1076 gettimeofday(&tv_even, (struct timezone *)NULL); 1398 gettimeofday(&tv_even, (struct timezone *)NULL);
1077 1399
1078 child_pid = fork(); 1400 child_pid = fork();
@@ -1095,14 +1417,17 @@ int fork_it(char **argv)
1095 exit(1); 1417 exit(1);
1096 } 1418 }
1097 } 1419 }
1098 get_counters(cnt_odd); 1420 /*
1421 * n.b. fork_it() does not check for errors from for_all_cpus()
1422 * because re-starting is problematic when forking
1423 */
1424 for_all_cpus(get_counters, ODD_COUNTERS);
1099 gettimeofday(&tv_odd, (struct timezone *)NULL); 1425 gettimeofday(&tv_odd, (struct timezone *)NULL);
1100 retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
1101
1102 timersub(&tv_odd, &tv_even, &tv_delta); 1426 timersub(&tv_odd, &tv_even, &tv_delta);
1103 compute_average(cnt_delta, cnt_average); 1427 for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS);
1104 if (!retval) 1428 compute_average(EVEN_COUNTERS);
1105 print_counters(cnt_delta); 1429 format_all_counters(EVEN_COUNTERS);
1430 flush_stderr();
1106 1431
1107 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0); 1432 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
1108 1433
@@ -1115,8 +1440,14 @@ void cmdline(int argc, char **argv)
1115 1440
1116 progname = argv[0]; 1441 progname = argv[0];
1117 1442
1118 while ((opt = getopt(argc, argv, "+svi:M:")) != -1) { 1443 while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
1119 switch (opt) { 1444 switch (opt) {
1445 case 'c':
1446 show_core_only++;
1447 break;
1448 case 'p':
1449 show_pkg_only++;
1450 break;
1120 case 's': 1451 case 's':
1121 summary_only++; 1452 summary_only++;
1122 break; 1453 break;
@@ -1142,10 +1473,8 @@ int main(int argc, char **argv)
1142 cmdline(argc, argv); 1473 cmdline(argc, argv);
1143 1474
1144 if (verbose > 1) 1475 if (verbose > 1)
1145 fprintf(stderr, "turbostat Dec 6, 2010" 1476 fprintf(stderr, "turbostat v2.0 May 16, 2012"
1146 " - Len Brown <lenb@kernel.org>\n"); 1477 " - Len Brown <lenb@kernel.org>\n");
1147 if (verbose > 1)
1148 fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
1149 1478
1150 turbostat_init(); 1479 turbostat_init();
1151 1480
diff --git a/tools/testing/fault-injection/failcmd.sh b/tools/testing/fault-injection/failcmd.sh
new file mode 100644
index 000000000000..78a9ed7fecdb
--- /dev/null
+++ b/tools/testing/fault-injection/failcmd.sh
@@ -0,0 +1,219 @@
1#!/bin/bash
2#
3# NAME
4# failcmd.sh - run a command with injecting slab/page allocation failures
5#
6# SYNOPSIS
7# failcmd.sh --help
8# failcmd.sh [<options>] command [arguments]
9#
10# DESCRIPTION
11# Run command with injecting slab/page allocation failures by fault
12# injection.
13#
14# NOTE: you need to run this script as root.
15#
16
17usage()
18{
19 cat >&2 <<EOF
20Usage: $0 [options] command [arguments]
21
22OPTIONS
23 -p percent
24 --probability=percent
25 likelihood of failure injection, in percent.
26 Default value is 1
27
28 -t value
29 --times=value
30 specifies how many times failures may happen at most.
31 Default value is 1
32
33 --oom-kill-allocating-task=value
34 set /proc/sys/vm/oom_kill_allocating_task to specified value
35 before running the command.
36 Default value is 1
37
38 -h, --help
39 Display a usage message and exit
40
41 --interval=value, --space=value, --verbose=value, --task-filter=value,
42 --stacktrace-depth=value, --require-start=value, --require-end=value,
43 --reject-start=value, --reject-end=value, --ignore-gfp-wait=value
44 See Documentation/fault-injection/fault-injection.txt for more
45 information
46
47 failslab options:
48 --cache-filter=value
49
50 fail_page_alloc options:
51 --ignore-gfp-highmem=value, --min-order=value
52
53ENVIRONMENT
54 FAILCMD_TYPE
55 The following values for FAILCMD_TYPE are recognized:
56
57 failslab
58 inject slab allocation failures
59 fail_page_alloc
60 inject page allocation failures
61
62 If FAILCMD_TYPE is not defined, then failslab is used.
63EOF
64}
65
66if [ $UID != 0 ]; then
67 echo must be run as root >&2
68 exit 1
69fi
70
71DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3}'`
72
73if [ ! -d "$DEBUGFS" ]; then
74 echo debugfs is not mounted >&2
75 exit 1
76fi
77
78FAILCMD_TYPE=${FAILCMD_TYPE:-failslab}
79FAULTATTR=$DEBUGFS/$FAILCMD_TYPE
80
81if [ ! -d $FAULTATTR ]; then
82 echo $FAILCMD_TYPE is not available >&2
83 exit 1
84fi
85
86LONGOPTS=probability:,interval:,times:,space:,verbose:,task-filter:
87LONGOPTS=$LONGOPTS,stacktrace-depth:,require-start:,require-end:
88LONGOPTS=$LONGOPTS,reject-start:,reject-end:,oom-kill-allocating-task:,help
89
90if [ $FAILCMD_TYPE = failslab ]; then
91 LONGOPTS=$LONGOPTS,ignore-gfp-wait:,cache-filter:
92elif [ $FAILCMD_TYPE = fail_page_alloc ]; then
93 LONGOPTS=$LONGOPTS,ignore-gfp-wait:,ignore-gfp-highmem:,min-order:
94fi
95
96TEMP=`getopt -o p:i:t:s:v:h --long $LONGOPTS -n 'failcmd.sh' -- "$@"`
97
98if [ $? != 0 ]; then
99 usage
100 exit 1
101fi
102
103eval set -- "$TEMP"
104
105fault_attr_default()
106{
107 echo N > $FAULTATTR/task-filter
108 echo 0 > $FAULTATTR/probability
109 echo 1 > $FAULTATTR/times
110}
111
112fault_attr_default
113
114oom_kill_allocating_task_saved=`cat /proc/sys/vm/oom_kill_allocating_task`
115
116restore_values()
117{
118 fault_attr_default
119 echo $oom_kill_allocating_task_saved \
120 > /proc/sys/vm/oom_kill_allocating_task
121}
122
123#
124# Default options
125#
126declare -i oom_kill_allocating_task=1
127declare task_filter=Y
128declare -i probability=1
129declare -i times=1
130
131while true; do
132 case "$1" in
133 -p|--probability)
134 probability=$2
135 shift 2
136 ;;
137 -i|--interval)
138 echo $2 > $FAULTATTR/interval
139 shift 2
140 ;;
141 -t|--times)
142 times=$2
143 shift 2
144 ;;
145 -s|--space)
146 echo $2 > $FAULTATTR/space
147 shift 2
148 ;;
149 -v|--verbose)
150 echo $2 > $FAULTATTR/verbose
151 shift 2
152 ;;
153 --task-filter)
154 task_filter=$2
155 shift 2
156 ;;
157 --stacktrace-depth)
158 echo $2 > $FAULTATTR/stacktrace-depth
159 shift 2
160 ;;
161 --require-start)
162 echo $2 > $FAULTATTR/require-start
163 shift 2
164 ;;
165 --require-end)
166 echo $2 > $FAULTATTR/require-end
167 shift 2
168 ;;
169 --reject-start)
170 echo $2 > $FAULTATTR/reject-start
171 shift 2
172 ;;
173 --reject-end)
174 echo $2 > $FAULTATTR/reject-end
175 shift 2
176 ;;
177 --oom-kill-allocating-task)
178 oom_kill_allocating_task=$2
179 shift 2
180 ;;
181 --ignore-gfp-wait)
182 echo $2 > $FAULTATTR/ignore-gfp-wait
183 shift 2
184 ;;
185 --cache-filter)
186 echo $2 > $FAULTATTR/cache_filter
187 shift 2
188 ;;
189 --ignore-gfp-highmem)
190 echo $2 > $FAULTATTR/ignore-gfp-highmem
191 shift 2
192 ;;
193 --min-order)
194 echo $2 > $FAULTATTR/min-order
195 shift 2
196 ;;
197 -h|--help)
198 usage
199 exit 0
200 shift
201 ;;
202 --)
203 shift
204 break
205 ;;
206 esac
207done
208
209[ -z "$1" ] && exit 0
210
211echo $oom_kill_allocating_task > /proc/sys/vm/oom_kill_allocating_task
212echo $task_filter > $FAULTATTR/task-filter
213echo $probability > $FAULTATTR/probability
214echo $times > $FAULTATTR/times
215
216trap "restore_values" SIGINT SIGTERM EXIT
217
218cmd="echo 1 > /proc/self/make-it-fail && exec $@"
219bash -c "$cmd"
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 292b13ad03f5..52b7959cd513 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -52,6 +52,7 @@ my %default = (
52 "STOP_AFTER_SUCCESS" => 10, 52 "STOP_AFTER_SUCCESS" => 10,
53 "STOP_AFTER_FAILURE" => 60, 53 "STOP_AFTER_FAILURE" => 60,
54 "STOP_TEST_AFTER" => 600, 54 "STOP_TEST_AFTER" => 600,
55 "MAX_MONITOR_WAIT" => 1800,
55 56
56# required, and we will ask users if they don't have them but we keep the default 57# required, and we will ask users if they don't have them but we keep the default
57# value something that is common. 58# value something that is common.
@@ -77,6 +78,11 @@ my $output_config;
77my $test_type; 78my $test_type;
78my $build_type; 79my $build_type;
79my $build_options; 80my $build_options;
81my $final_post_ktest;
82my $pre_ktest;
83my $post_ktest;
84my $pre_test;
85my $post_test;
80my $pre_build; 86my $pre_build;
81my $post_build; 87my $post_build;
82my $pre_build_die; 88my $pre_build_die;
@@ -93,6 +99,7 @@ my $reboot_on_success;
93my $die_on_failure; 99my $die_on_failure;
94my $powercycle_after_reboot; 100my $powercycle_after_reboot;
95my $poweroff_after_halt; 101my $poweroff_after_halt;
102my $max_monitor_wait;
96my $ssh_exec; 103my $ssh_exec;
97my $scp_to_target; 104my $scp_to_target;
98my $scp_to_target_install; 105my $scp_to_target_install;
@@ -101,6 +108,7 @@ my $grub_menu;
101my $grub_number; 108my $grub_number;
102my $target; 109my $target;
103my $make; 110my $make;
111my $pre_install;
104my $post_install; 112my $post_install;
105my $no_install; 113my $no_install;
106my $noclean; 114my $noclean;
@@ -167,6 +175,7 @@ my $bisect_check;
167 175
168my $config_bisect; 176my $config_bisect;
169my $config_bisect_type; 177my $config_bisect_type;
178my $config_bisect_check;
170 179
171my $patchcheck_type; 180my $patchcheck_type;
172my $patchcheck_start; 181my $patchcheck_start;
@@ -182,6 +191,9 @@ my $newconfig = 0;
182my %entered_configs; 191my %entered_configs;
183my %config_help; 192my %config_help;
184my %variable; 193my %variable;
194
195# force_config is the list of configs that we force enabled (or disabled)
196# in a .config file. The MIN_CONFIG and ADD_CONFIG configs.
185my %force_config; 197my %force_config;
186 198
187# do not force reboots on config problems 199# do not force reboots on config problems
@@ -197,6 +209,10 @@ my %option_map = (
197 "OUTPUT_DIR" => \$outputdir, 209 "OUTPUT_DIR" => \$outputdir,
198 "BUILD_DIR" => \$builddir, 210 "BUILD_DIR" => \$builddir,
199 "TEST_TYPE" => \$test_type, 211 "TEST_TYPE" => \$test_type,
212 "PRE_KTEST" => \$pre_ktest,
213 "POST_KTEST" => \$post_ktest,
214 "PRE_TEST" => \$pre_test,
215 "POST_TEST" => \$post_test,
200 "BUILD_TYPE" => \$build_type, 216 "BUILD_TYPE" => \$build_type,
201 "BUILD_OPTIONS" => \$build_options, 217 "BUILD_OPTIONS" => \$build_options,
202 "PRE_BUILD" => \$pre_build, 218 "PRE_BUILD" => \$pre_build,
@@ -216,6 +232,7 @@ my %option_map = (
216 "ADD_CONFIG" => \$addconfig, 232 "ADD_CONFIG" => \$addconfig,
217 "REBOOT_TYPE" => \$reboot_type, 233 "REBOOT_TYPE" => \$reboot_type,
218 "GRUB_MENU" => \$grub_menu, 234 "GRUB_MENU" => \$grub_menu,
235 "PRE_INSTALL" => \$pre_install,
219 "POST_INSTALL" => \$post_install, 236 "POST_INSTALL" => \$post_install,
220 "NO_INSTALL" => \$no_install, 237 "NO_INSTALL" => \$no_install,
221 "REBOOT_SCRIPT" => \$reboot_script, 238 "REBOOT_SCRIPT" => \$reboot_script,
@@ -228,6 +245,7 @@ my %option_map = (
228 "POWER_OFF" => \$power_off, 245 "POWER_OFF" => \$power_off,
229 "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot, 246 "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot,
230 "POWEROFF_AFTER_HALT" => \$poweroff_after_halt, 247 "POWEROFF_AFTER_HALT" => \$poweroff_after_halt,
248 "MAX_MONITOR_WAIT" => \$max_monitor_wait,
231 "SLEEP_TIME" => \$sleep_time, 249 "SLEEP_TIME" => \$sleep_time,
232 "BISECT_SLEEP_TIME" => \$bisect_sleep_time, 250 "BISECT_SLEEP_TIME" => \$bisect_sleep_time,
233 "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time, 251 "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time,
@@ -272,6 +290,7 @@ my %option_map = (
272 290
273 "CONFIG_BISECT" => \$config_bisect, 291 "CONFIG_BISECT" => \$config_bisect,
274 "CONFIG_BISECT_TYPE" => \$config_bisect_type, 292 "CONFIG_BISECT_TYPE" => \$config_bisect_type,
293 "CONFIG_BISECT_CHECK" => \$config_bisect_check,
275 294
276 "PATCHCHECK_TYPE" => \$patchcheck_type, 295 "PATCHCHECK_TYPE" => \$patchcheck_type,
277 "PATCHCHECK_START" => \$patchcheck_start, 296 "PATCHCHECK_START" => \$patchcheck_start,
@@ -604,6 +623,10 @@ sub process_compare {
604 return $lval eq $rval; 623 return $lval eq $rval;
605 } elsif ($cmp eq "!=") { 624 } elsif ($cmp eq "!=") {
606 return $lval ne $rval; 625 return $lval ne $rval;
626 } elsif ($cmp eq "=~") {
627 return $lval =~ m/$rval/;
628 } elsif ($cmp eq "!~") {
629 return $lval !~ m/$rval/;
607 } 630 }
608 631
609 my $statement = "$lval $cmp $rval"; 632 my $statement = "$lval $cmp $rval";
@@ -659,7 +682,7 @@ sub process_expression {
659 } 682 }
660 } 683 }
661 684
662 if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) { 685 if ($val =~ /(.*)(==|\!=|>=|<=|>|<|=~|\!~)(.*)/) {
663 my $ret = process_compare($1, $2, $3); 686 my $ret = process_compare($1, $2, $3);
664 if ($ret < 0) { 687 if ($ret < 0) {
665 die "$name: $.: Unable to process comparison\n"; 688 die "$name: $.: Unable to process comparison\n";
@@ -1117,7 +1140,11 @@ sub reboot {
1117 } 1140 }
1118 1141
1119 if (defined($time)) { 1142 if (defined($time)) {
1120 wait_for_monitor($time, $reboot_success_line); 1143 if (wait_for_monitor($time, $reboot_success_line)) {
1144 # reboot got stuck?
1145 doprint "Reboot did not finish. Forcing power cycle\n";
1146 run_command "$power_cycle";
1147 }
1121 end_monitor; 1148 end_monitor;
1122 } 1149 }
1123} 1150}
@@ -1212,6 +1239,11 @@ sub wait_for_monitor {
1212 my $full_line = ""; 1239 my $full_line = "";
1213 my $line; 1240 my $line;
1214 my $booted = 0; 1241 my $booted = 0;
1242 my $start_time = time;
1243 my $skip_call_trace = 0;
1244 my $bug = 0;
1245 my $bug_ignored = 0;
1246 my $now;
1215 1247
1216 doprint "** Wait for monitor to settle down **\n"; 1248 doprint "** Wait for monitor to settle down **\n";
1217 1249
@@ -1227,11 +1259,39 @@ sub wait_for_monitor {
1227 $booted = 1; 1259 $booted = 1;
1228 } 1260 }
1229 1261
1262 if ($full_line =~ /\[ backtrace testing \]/) {
1263 $skip_call_trace = 1;
1264 }
1265
1266 if ($full_line =~ /call trace:/i) {
1267 if (!$bug && !$skip_call_trace) {
1268 if ($ignore_errors) {
1269 $bug_ignored = 1;
1270 } else {
1271 $bug = 1;
1272 }
1273 }
1274 }
1275
1276 if ($full_line =~ /\[ end of backtrace testing \]/) {
1277 $skip_call_trace = 0;
1278 }
1279
1280 if ($full_line =~ /Kernel panic -/) {
1281 $bug = 1;
1282 }
1283
1230 if ($line =~ /\n/) { 1284 if ($line =~ /\n/) {
1231 $full_line = ""; 1285 $full_line = "";
1232 } 1286 }
1287 $now = time;
1288 if ($now - $start_time >= $max_monitor_wait) {
1289 doprint "Exiting monitor flush due to hitting MAX_MONITOR_WAIT\n";
1290 return 1;
1291 }
1233 } 1292 }
1234 print "** Monitor flushed **\n"; 1293 print "** Monitor flushed **\n";
1294 return $bug;
1235} 1295}
1236 1296
1237sub save_logs { 1297sub save_logs {
@@ -1273,6 +1333,10 @@ sub save_logs {
1273 1333
1274sub fail { 1334sub fail {
1275 1335
1336 if (defined($post_test)) {
1337 run_command $post_test;
1338 }
1339
1276 if ($die_on_failure) { 1340 if ($die_on_failure) {
1277 dodie @_; 1341 dodie @_;
1278 } 1342 }
@@ -1656,6 +1720,12 @@ sub install {
1656 1720
1657 return if ($no_install); 1721 return if ($no_install);
1658 1722
1723 if (defined($pre_install)) {
1724 my $cp_pre_install = eval_kernel_version $pre_install;
1725 run_command "$cp_pre_install" or
1726 dodie "Failed to run pre install";
1727 }
1728
1659 my $cp_target = eval_kernel_version $target_image; 1729 my $cp_target = eval_kernel_version $target_image;
1660 1730
1661 run_scp_install "$outputdir/$build_target", "$cp_target" or 1731 run_scp_install "$outputdir/$build_target", "$cp_target" or
@@ -1814,6 +1884,7 @@ sub make_oldconfig {
1814sub load_force_config { 1884sub load_force_config {
1815 my ($config) = @_; 1885 my ($config) = @_;
1816 1886
1887 doprint "Loading force configs from $config\n";
1817 open(IN, $config) or 1888 open(IN, $config) or
1818 dodie "failed to read $config"; 1889 dodie "failed to read $config";
1819 while (<IN>) { 1890 while (<IN>) {
@@ -1937,6 +2008,10 @@ sub halt {
1937sub success { 2008sub success {
1938 my ($i) = @_; 2009 my ($i) = @_;
1939 2010
2011 if (defined($post_test)) {
2012 run_command $post_test;
2013 }
2014
1940 $successes++; 2015 $successes++;
1941 2016
1942 my $name = ""; 2017 my $name = "";
@@ -2003,6 +2078,7 @@ sub do_run_test {
2003 my $line; 2078 my $line;
2004 my $full_line; 2079 my $full_line;
2005 my $bug = 0; 2080 my $bug = 0;
2081 my $bug_ignored = 0;
2006 2082
2007 wait_for_monitor 1; 2083 wait_for_monitor 1;
2008 2084
@@ -2027,7 +2103,11 @@ sub do_run_test {
2027 doprint $line; 2103 doprint $line;
2028 2104
2029 if ($full_line =~ /call trace:/i) { 2105 if ($full_line =~ /call trace:/i) {
2030 $bug = 1; 2106 if ($ignore_errors) {
2107 $bug_ignored = 1;
2108 } else {
2109 $bug = 1;
2110 }
2031 } 2111 }
2032 2112
2033 if ($full_line =~ /Kernel panic -/) { 2113 if ($full_line =~ /Kernel panic -/) {
@@ -2040,6 +2120,10 @@ sub do_run_test {
2040 } 2120 }
2041 } while (!$child_done && !$bug); 2121 } while (!$child_done && !$bug);
2042 2122
2123 if (!$bug && $bug_ignored) {
2124 doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
2125 }
2126
2043 if ($bug) { 2127 if ($bug) {
2044 my $failure_start = time; 2128 my $failure_start = time;
2045 my $now; 2129 my $now;
@@ -2362,9 +2446,24 @@ sub bisect {
2362 success $i; 2446 success $i;
2363} 2447}
2364 2448
2449# config_ignore holds the configs that were set (or unset) for
2450# a good config and we will ignore these configs for the rest
2451# of a config bisect. These configs stay as they were.
2365my %config_ignore; 2452my %config_ignore;
2453
2454# config_set holds what all configs were set as.
2366my %config_set; 2455my %config_set;
2367 2456
2457# config_off holds the set of configs that the bad config had disabled.
2458# We need to record them and set them in the .config when running
2459# oldnoconfig, because oldnoconfig does not turn off new symbols, but
2460# instead just keeps the defaults.
2461my %config_off;
2462
2463# config_off_tmp holds a set of configs to turn off for now
2464my @config_off_tmp;
2465
2466# config_list is the set of configs that are being tested
2368my %config_list; 2467my %config_list;
2369my %null_config; 2468my %null_config;
2370 2469
@@ -2443,12 +2542,21 @@ sub create_config {
2443 } 2542 }
2444 } 2543 }
2445 2544
2545 # turn off configs to keep off
2546 foreach my $config (keys %config_off) {
2547 print OUT "# $config is not set\n";
2548 }
2549
2550 # turn off configs that should be off for now
2551 foreach my $config (@config_off_tmp) {
2552 print OUT "# $config is not set\n";
2553 }
2554
2446 foreach my $config (keys %config_ignore) { 2555 foreach my $config (keys %config_ignore) {
2447 print OUT "$config_ignore{$config}\n"; 2556 print OUT "$config_ignore{$config}\n";
2448 } 2557 }
2449 close(OUT); 2558 close(OUT);
2450 2559
2451# exit;
2452 make_oldconfig; 2560 make_oldconfig;
2453} 2561}
2454 2562
@@ -2525,6 +2633,13 @@ sub run_config_bisect {
2525 do { 2633 do {
2526 my @tophalf = @start_list[0 .. $half]; 2634 my @tophalf = @start_list[0 .. $half];
2527 2635
2636 # keep the bottom half off
2637 if ($half < $#start_list) {
2638 @config_off_tmp = @start_list[$half + 1 .. $#start_list];
2639 } else {
2640 @config_off_tmp = ();
2641 }
2642
2528 create_config @tophalf; 2643 create_config @tophalf;
2529 read_current_config \%current_config; 2644 read_current_config \%current_config;
2530 2645
@@ -2541,7 +2656,11 @@ sub run_config_bisect {
2541 if (!$found) { 2656 if (!$found) {
2542 # try the other half 2657 # try the other half
2543 doprint "Top half produced no set configs, trying bottom half\n"; 2658 doprint "Top half produced no set configs, trying bottom half\n";
2659
2660 # keep the top half off
2661 @config_off_tmp = @tophalf;
2544 @tophalf = @start_list[$half + 1 .. $#start_list]; 2662 @tophalf = @start_list[$half + 1 .. $#start_list];
2663
2545 create_config @tophalf; 2664 create_config @tophalf;
2546 read_current_config \%current_config; 2665 read_current_config \%current_config;
2547 foreach my $config (@tophalf) { 2666 foreach my $config (@tophalf) {
@@ -2679,6 +2798,10 @@ sub config_bisect {
2679 $added_configs{$2} = $1; 2798 $added_configs{$2} = $1;
2680 $config_list{$2} = $1; 2799 $config_list{$2} = $1;
2681 } 2800 }
2801 } elsif (/^# ((CONFIG\S*).*)/) {
2802 # Keep these configs disabled
2803 $config_set{$2} = $1;
2804 $config_off{$2} = $1;
2682 } 2805 }
2683 } 2806 }
2684 close(IN); 2807 close(IN);
@@ -2701,6 +2824,8 @@ sub config_bisect {
2701 my %config_test; 2824 my %config_test;
2702 my $once = 0; 2825 my $once = 0;
2703 2826
2827 @config_off_tmp = ();
2828
2704 # Sometimes kconfig does weird things. We must make sure 2829 # Sometimes kconfig does weird things. We must make sure
2705 # that the config we autocreate has everything we need 2830 # that the config we autocreate has everything we need
2706 # to test, otherwise we may miss testing configs, or 2831 # to test, otherwise we may miss testing configs, or
@@ -2719,6 +2844,18 @@ sub config_bisect {
2719 } 2844 }
2720 } 2845 }
2721 my $ret; 2846 my $ret;
2847
2848 if (defined($config_bisect_check) && $config_bisect_check) {
2849 doprint " Checking to make sure bad config with min config fails\n";
2850 create_config keys %config_list;
2851 $ret = run_config_bisect_test $config_bisect_type;
2852 if ($ret) {
2853 doprint " FAILED! Bad config with min config boots fine\n";
2854 return -1;
2855 }
2856 doprint " Bad config with min config fails as expected\n";
2857 }
2858
2722 do { 2859 do {
2723 $ret = run_config_bisect; 2860 $ret = run_config_bisect;
2724 } while (!$ret); 2861 } while (!$ret);
@@ -3510,6 +3647,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3510 3647
3511 $iteration = $i; 3648 $iteration = $i;
3512 3649
3650 undef %force_config;
3651
3513 my $makecmd = set_test_option("MAKE_CMD", $i); 3652 my $makecmd = set_test_option("MAKE_CMD", $i);
3514 3653
3515 # Load all the options into their mapped variable names 3654 # Load all the options into their mapped variable names
@@ -3519,6 +3658,18 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3519 3658
3520 $start_minconfig_defined = 1; 3659 $start_minconfig_defined = 1;
3521 3660
3661 # The first test may override the PRE_KTEST option
3662 if (defined($pre_ktest) && $i == 1) {
3663 doprint "\n";
3664 run_command $pre_ktest;
3665 }
3666
3667 # Any test can override the POST_KTEST option
3668 # The last test takes precedence.
3669 if (defined($post_ktest)) {
3670 $final_post_ktest = $post_ktest;
3671 }
3672
3522 if (!defined($start_minconfig)) { 3673 if (!defined($start_minconfig)) {
3523 $start_minconfig_defined = 0; 3674 $start_minconfig_defined = 0;
3524 $start_minconfig = $minconfig; 3675 $start_minconfig = $minconfig;
@@ -3573,6 +3724,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3573 doprint "\n\n"; 3724 doprint "\n\n";
3574 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n"; 3725 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n";
3575 3726
3727 if (defined($pre_test)) {
3728 run_command $pre_test;
3729 }
3730
3576 unlink $dmesg; 3731 unlink $dmesg;
3577 unlink $buildlog; 3732 unlink $buildlog;
3578 unlink $testlog; 3733 unlink $testlog;
@@ -3638,6 +3793,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3638 success $i; 3793 success $i;
3639} 3794}
3640 3795
3796if (defined($final_post_ktest)) {
3797 run_command $final_post_ktest;
3798}
3799
3641if ($opt{"POWEROFF_ON_SUCCESS"}) { 3800if ($opt{"POWEROFF_ON_SUCCESS"}) {
3642 halt; 3801 halt;
3643} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot && $reboot_success) { 3802} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot && $reboot_success) {
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index cf362b3d1ec9..de28a0a3b8fc 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -376,6 +376,24 @@
376# DEFAULTS 376# DEFAULTS
377# DEFAULTS SKIP 377# DEFAULTS SKIP
378 378
379# If you want to execute some command before the first test runs
380# you can set this option. Note, it can be set as a default option
381# or an option in the first test case. All other test cases will
382# ignore it. If both the default and first test have this option
383# set, then the first test will take precedence.
384#
385# default (undefined)
386#PRE_KTEST = ${SSH} ~/set_up_test
387
388# If you want to execute some command after all the tests have
389# completed, you can set this option. Note, it can be set as a
390# default or any test case can override it. If multiple test cases
391# set this option, then the last test case that set it will take
392# precedence
393#
394# default (undefined)
395#POST_KTEST = ${SSH} ~/dismantle_test
396
379# The default test type (default test) 397# The default test type (default test)
380# The test types may be: 398# The test types may be:
381# build - only build the kernel, do nothing else 399# build - only build the kernel, do nothing else
@@ -408,6 +426,14 @@
408# (default "") 426# (default "")
409#BUILD_OPTIONS = -j20 427#BUILD_OPTIONS = -j20
410 428
429# If you need to do some special handling before installing
430# you can add a script with this option.
431# The environment variable KERNEL_VERSION will be set to the
432# kernel version that is used.
433#
434# default (undefined)
435#PRE_INSTALL = ssh user@target rm -rf '/lib/modules/*-test*'
436
411# If you need an initrd, you can add a script or code here to install 437# If you need an initrd, you can add a script or code here to install
412# it. The environment variable KERNEL_VERSION will be set to the 438# it. The environment variable KERNEL_VERSION will be set to the
413# kernel version that is used. Remember to add the initrd line 439# kernel version that is used. Remember to add the initrd line
@@ -426,6 +452,18 @@
426# (default 0) 452# (default 0)
427#NO_INSTALL = 1 453#NO_INSTALL = 1
428 454
455# If there is a command that you want to run before the individual test
456# case executes, then you can set this option
457#
458# default (undefined)
459#PRE_TEST = ${SSH} reboot_to_special_kernel
460
461# If there is a command you want to run after the individual test case
462# completes, then you can set this option.
463#
464# default (undefined)
465#POST_TEST = cd ${BUILD_DIR}; git reset --hard
466
429# If there is a script that you require to run before the build is done 467# If there is a script that you require to run before the build is done
430# you can specify it with PRE_BUILD. 468# you can specify it with PRE_BUILD.
431# 469#
@@ -657,6 +695,14 @@
657# (default 60) 695# (default 60)
658#BISECT_SLEEP_TIME = 60 696#BISECT_SLEEP_TIME = 60
659 697
698# The max wait time (in seconds) for waiting for the console to finish.
699# If for some reason, the console is outputting content without
700# ever finishing, this will cause ktest to get stuck. This
701# option is the max time ktest will wait for the monitor (console)
702# to settle down before continuing.
703# (default 1800)
704#MAX_MONITOR_WAIT
705
660# The time in between patch checks to sleep (in seconds) 706# The time in between patch checks to sleep (in seconds)
661# (default 60) 707# (default 60)
662#PATCHCHECK_SLEEP_TIME = 60 708#PATCHCHECK_SLEEP_TIME = 60
@@ -1039,6 +1085,12 @@
1039# can specify it with CONFIG_BISECT_GOOD. Otherwise 1085# can specify it with CONFIG_BISECT_GOOD. Otherwise
1040# the MIN_CONFIG is the base. 1086# the MIN_CONFIG is the base.
1041# 1087#
1088# CONFIG_BISECT_CHECK (optional)
1089# Set this to 1 if you want to confirm that the config ktest
1090# generates (the bad config with the min config) is still bad.
1091# It may be that the min config fixes what broke the bad config
1092# and the test will not return a result.
1093#
1042# Example: 1094# Example:
1043# TEST_START 1095# TEST_START
1044# TEST_TYPE = config_bisect 1096# TEST_TYPE = config_bisect
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index a4162e15c25f..85baf11e2acd 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,4 @@
1TARGETS = breakpoints kcmp mqueue vm 1TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
2 2
3all: 3all:
4 for TARGET in $(TARGETS); do \ 4 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
new file mode 100644
index 000000000000..7c9c20ff578a
--- /dev/null
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -0,0 +1,6 @@
1all:
2
3run_tests:
4 ./on-off-test.sh
5
6clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
new file mode 100644
index 000000000000..bdde7cf428bb
--- /dev/null
+++ b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
@@ -0,0 +1,221 @@
1#!/bin/bash
2
3SYSFS=
4
5prerequisite()
6{
7 msg="skip all tests:"
8
9 if [ $UID != 0 ]; then
10 echo $msg must be run as root >&2
11 exit 0
12 fi
13
14 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
15
16 if [ ! -d "$SYSFS" ]; then
17 echo $msg sysfs is not mounted >&2
18 exit 0
19 fi
20
21 if ! ls $SYSFS/devices/system/cpu/cpu* > /dev/null 2>&1; then
22 echo $msg cpu hotplug is not supported >&2
23 exit 0
24 fi
25}
26
27#
28# list all hot-pluggable CPUs
29#
30hotpluggable_cpus()
31{
32 local state=${1:-.\*}
33
34 for cpu in $SYSFS/devices/system/cpu/cpu*; do
35 if [ -f $cpu/online ] && grep -q $state $cpu/online; then
36 echo ${cpu##/*/cpu}
37 fi
38 done
39}
40
41hotplaggable_offline_cpus()
42{
43 hotpluggable_cpus 0
44}
45
46hotpluggable_online_cpus()
47{
48 hotpluggable_cpus 1
49}
50
51cpu_is_online()
52{
53 grep -q 1 $SYSFS/devices/system/cpu/cpu$1/online
54}
55
56cpu_is_offline()
57{
58 grep -q 0 $SYSFS/devices/system/cpu/cpu$1/online
59}
60
61online_cpu()
62{
63 echo 1 > $SYSFS/devices/system/cpu/cpu$1/online
64}
65
66offline_cpu()
67{
68 echo 0 > $SYSFS/devices/system/cpu/cpu$1/online
69}
70
71online_cpu_expect_success()
72{
73 local cpu=$1
74
75 if ! online_cpu $cpu; then
76 echo $FUNCNAME $cpu: unexpected fail >&2
77 elif ! cpu_is_online $cpu; then
78 echo $FUNCNAME $cpu: unexpected offline >&2
79 fi
80}
81
82online_cpu_expect_fail()
83{
84 local cpu=$1
85
86 if online_cpu $cpu 2> /dev/null; then
87 echo $FUNCNAME $cpu: unexpected success >&2
88 elif ! cpu_is_offline $cpu; then
89 echo $FUNCNAME $cpu: unexpected online >&2
90 fi
91}
92
93offline_cpu_expect_success()
94{
95 local cpu=$1
96
97 if ! offline_cpu $cpu; then
98 echo $FUNCNAME $cpu: unexpected fail >&2
99 elif ! cpu_is_offline $cpu; then
100 echo $FUNCNAME $cpu: unexpected offline >&2
101 fi
102}
103
104offline_cpu_expect_fail()
105{
106 local cpu=$1
107
108 if offline_cpu $cpu 2> /dev/null; then
109 echo $FUNCNAME $cpu: unexpected success >&2
110 elif ! cpu_is_online $cpu; then
111 echo $FUNCNAME $cpu: unexpected offline >&2
112 fi
113}
114
115error=-12
116priority=0
117
118while getopts e:hp: opt; do
119 case $opt in
120 e)
121 error=$OPTARG
122 ;;
123 h)
124 echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
125 exit
126 ;;
127 p)
128 priority=$OPTARG
129 ;;
130 esac
131done
132
133if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
134 echo "error code must be -4095 <= errno < 0" >&2
135 exit 1
136fi
137
138prerequisite
139
140#
141# Online all hot-pluggable CPUs
142#
143for cpu in `hotplaggable_offline_cpus`; do
144 online_cpu_expect_success $cpu
145done
146
147#
148# Offline all hot-pluggable CPUs
149#
150for cpu in `hotpluggable_online_cpus`; do
151 offline_cpu_expect_success $cpu
152done
153
154#
155# Online all hot-pluggable CPUs again
156#
157for cpu in `hotplaggable_offline_cpus`; do
158 online_cpu_expect_success $cpu
159done
160
161#
162# Test with cpu notifier error injection
163#
164
165DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
166NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
167
168prerequisite_extra()
169{
170 msg="skip extra tests:"
171
172 /sbin/modprobe -q -r cpu-notifier-error-inject
173 /sbin/modprobe -q cpu-notifier-error-inject priority=$priority
174
175 if [ ! -d "$DEBUGFS" ]; then
176 echo $msg debugfs is not mounted >&2
177 exit 0
178 fi
179
180 if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
181 echo $msg cpu-notifier-error-inject module is not available >&2
182 exit 0
183 fi
184}
185
186prerequisite_extra
187
188#
189# Offline all hot-pluggable CPUs
190#
191echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
192for cpu in `hotpluggable_online_cpus`; do
193 offline_cpu_expect_success $cpu
194done
195
196#
197# Test CPU hot-add error handling (offline => online)
198#
199echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
200for cpu in `hotplaggable_offline_cpus`; do
201 online_cpu_expect_fail $cpu
202done
203
204#
205# Online all hot-pluggable CPUs
206#
207echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
208for cpu in `hotplaggable_offline_cpus`; do
209 online_cpu_expect_success $cpu
210done
211
212#
213# Test CPU hot-remove error handling (online => offline)
214#
215echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
216for cpu in `hotpluggable_online_cpus`; do
217 offline_cpu_expect_fail $cpu
218done
219
220echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
221/sbin/modprobe -q -r cpu-notifier-error-inject
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
new file mode 100644
index 000000000000..7c9c20ff578a
--- /dev/null
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -0,0 +1,6 @@
1all:
2
3run_tests:
4 ./on-off-test.sh
5
6clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
new file mode 100644
index 000000000000..a2816f631542
--- /dev/null
+++ b/tools/testing/selftests/memory-hotplug/on-off-test.sh
@@ -0,0 +1,230 @@
1#!/bin/bash
2
3SYSFS=
4
5prerequisite()
6{
7 msg="skip all tests:"
8
9 if [ $UID != 0 ]; then
10 echo $msg must be run as root >&2
11 exit 0
12 fi
13
14 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
15
16 if [ ! -d "$SYSFS" ]; then
17 echo $msg sysfs is not mounted >&2
18 exit 0
19 fi
20
21 if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
22 echo $msg memory hotplug is not supported >&2
23 exit 0
24 fi
25}
26
27#
28# list all hot-pluggable memory
29#
30hotpluggable_memory()
31{
32 local state=${1:-.\*}
33
34 for memory in $SYSFS/devices/system/memory/memory*; do
35 if grep -q 1 $memory/removable &&
36 grep -q $state $memory/state; then
37 echo ${memory##/*/memory}
38 fi
39 done
40}
41
42hotplaggable_offline_memory()
43{
44 hotpluggable_memory offline
45}
46
47hotpluggable_online_memory()
48{
49 hotpluggable_memory online
50}
51
52memory_is_online()
53{
54 grep -q online $SYSFS/devices/system/memory/memory$1/state
55}
56
57memory_is_offline()
58{
59 grep -q offline $SYSFS/devices/system/memory/memory$1/state
60}
61
62online_memory()
63{
64 echo online > $SYSFS/devices/system/memory/memory$1/state
65}
66
67offline_memory()
68{
69 echo offline > $SYSFS/devices/system/memory/memory$1/state
70}
71
72online_memory_expect_success()
73{
74 local memory=$1
75
76 if ! online_memory $memory; then
77 echo $FUNCNAME $memory: unexpected fail >&2
78 elif ! memory_is_online $memory; then
79 echo $FUNCNAME $memory: unexpected offline >&2
80 fi
81}
82
83online_memory_expect_fail()
84{
85 local memory=$1
86
87 if online_memory $memory 2> /dev/null; then
88 echo $FUNCNAME $memory: unexpected success >&2
89 elif ! memory_is_offline $memory; then
90 echo $FUNCNAME $memory: unexpected online >&2
91 fi
92}
93
94offline_memory_expect_success()
95{
96 local memory=$1
97
98 if ! offline_memory $memory; then
99 echo $FUNCNAME $memory: unexpected fail >&2
100 elif ! memory_is_offline $memory; then
101 echo $FUNCNAME $memory: unexpected offline >&2
102 fi
103}
104
105offline_memory_expect_fail()
106{
107 local memory=$1
108
109 if offline_memory $memory 2> /dev/null; then
110 echo $FUNCNAME $memory: unexpected success >&2
111 elif ! memory_is_online $memory; then
112 echo $FUNCNAME $memory: unexpected offline >&2
113 fi
114}
115
116error=-12
117priority=0
118ratio=10
119
120while getopts e:hp:r: opt; do
121 case $opt in
122 e)
123 error=$OPTARG
124 ;;
125 h)
126 echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
127 exit
128 ;;
129 p)
130 priority=$OPTARG
131 ;;
132 r)
133 ratio=$OPTARG
134 ;;
135 esac
136done
137
138if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
139 echo "error code must be -4095 <= errno < 0" >&2
140 exit 1
141fi
142
143prerequisite
144
145#
146# Online all hot-pluggable memory
147#
148for memory in `hotplaggable_offline_memory`; do
149 online_memory_expect_success $memory
150done
151
152#
153# Offline $ratio percent of hot-pluggable memory
154#
155for memory in `hotpluggable_online_memory`; do
156 if [ $((RANDOM % 100)) -lt $ratio ]; then
157 offline_memory_expect_success $memory
158 fi
159done
160
161#
162# Online all hot-pluggable memory again
163#
164for memory in `hotplaggable_offline_memory`; do
165 online_memory_expect_success $memory
166done
167
168#
169# Test with memory notifier error injection
170#
171
172DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
173NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
174
175prerequisite_extra()
176{
177 msg="skip extra tests:"
178
179 /sbin/modprobe -q -r memory-notifier-error-inject
180 /sbin/modprobe -q memory-notifier-error-inject priority=$priority
181
182 if [ ! -d "$DEBUGFS" ]; then
183 echo $msg debugfs is not mounted >&2
184 exit 0
185 fi
186
187 if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
188 echo $msg memory-notifier-error-inject module is not available >&2
189 exit 0
190 fi
191}
192
193prerequisite_extra
194
195#
196# Offline $ratio percent of hot-pluggable memory
197#
198echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
199for memory in `hotpluggable_online_memory`; do
200 if [ $((RANDOM % 100)) -lt $ratio ]; then
201 offline_memory_expect_success $memory
202 fi
203done
204
205#
206# Test memory hot-add error handling (offline => online)
207#
208echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
209for memory in `hotplaggable_offline_memory`; do
210 online_memory_expect_fail $memory
211done
212
213#
214# Online all hot-pluggable memory
215#
216echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
217for memory in `hotplaggable_offline_memory`; do
218 online_memory_expect_success $memory
219done
220
221#
222# Test memory hot-remove error handling (online => offline)
223#
224echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
225for memory in `hotpluggable_online_memory`; do
226 offline_memory_expect_fail $memory
227done
228
229echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
230/sbin/modprobe -q -r memory-notifier-error-inject
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 82d7c590c026..b0adb2710c02 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -425,7 +425,7 @@ int main (int argc, char **argv)
425 /* for easy use when hotplugging */ 425 /* for easy use when hotplugging */
426 device = getenv ("DEVICE"); 426 device = getenv ("DEVICE");
427 427
428 while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF) 428 while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
429 switch (c) { 429 switch (c) {
430 case 'D': /* device, if only one */ 430 case 'D': /* device, if only one */
431 device = optarg; 431 device = optarg;
@@ -468,10 +468,21 @@ int main (int argc, char **argv)
468 case 'h': 468 case 'h':
469 default: 469 default:
470usage: 470usage:
471 fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n" 471 fprintf (stderr,
472 "\t[-c iterations] [-t testnum]\n" 472 "usage: %s [options]\n"
473 "\t[-s packetsize] [-g sglen] [-v vary]\n", 473 "Options:\n"
474 argv [0]); 474 "\t-D dev only test specific device\n"
475 "\t-A usbfs-dir\n"
476 "\t-a test all recognized devices\n"
477 "\t-l loop forever(for stress test)\n"
478 "\t-t testnum only run specified case\n"
479 "\t-n no test running, show devices to be tested\n"
480 "Case arguments:\n"
481 "\t-c iterations default 1000\n"
482 "\t-s packetsize default 512\n"
483 "\t-g sglen default 32\n"
484 "\t-v vary default 512\n",
485 argv[0]);
475 return 1; 486 return 1;
476 } 487 }
477 if (optind != argc) 488 if (optind != argc)
diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c
index 164cbcf61106..808d5a9d5dcf 100644
--- a/tools/vm/slabinfo.c
+++ b/tools/vm/slabinfo.c
@@ -437,34 +437,34 @@ static void slab_stats(struct slabinfo *s)
437 printf("Fastpath %8lu %8lu %3lu %3lu\n", 437 printf("Fastpath %8lu %8lu %3lu %3lu\n",
438 s->alloc_fastpath, s->free_fastpath, 438 s->alloc_fastpath, s->free_fastpath,
439 s->alloc_fastpath * 100 / total_alloc, 439 s->alloc_fastpath * 100 / total_alloc,
440 s->free_fastpath * 100 / total_free); 440 total_free ? s->free_fastpath * 100 / total_free : 0);
441 printf("Slowpath %8lu %8lu %3lu %3lu\n", 441 printf("Slowpath %8lu %8lu %3lu %3lu\n",
442 total_alloc - s->alloc_fastpath, s->free_slowpath, 442 total_alloc - s->alloc_fastpath, s->free_slowpath,
443 (total_alloc - s->alloc_fastpath) * 100 / total_alloc, 443 (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
444 s->free_slowpath * 100 / total_free); 444 total_free ? s->free_slowpath * 100 / total_free : 0);
445 printf("Page Alloc %8lu %8lu %3lu %3lu\n", 445 printf("Page Alloc %8lu %8lu %3lu %3lu\n",
446 s->alloc_slab, s->free_slab, 446 s->alloc_slab, s->free_slab,
447 s->alloc_slab * 100 / total_alloc, 447 s->alloc_slab * 100 / total_alloc,
448 s->free_slab * 100 / total_free); 448 total_free ? s->free_slab * 100 / total_free : 0);
449 printf("Add partial %8lu %8lu %3lu %3lu\n", 449 printf("Add partial %8lu %8lu %3lu %3lu\n",
450 s->deactivate_to_head + s->deactivate_to_tail, 450 s->deactivate_to_head + s->deactivate_to_tail,
451 s->free_add_partial, 451 s->free_add_partial,
452 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc, 452 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
453 s->free_add_partial * 100 / total_free); 453 total_free ? s->free_add_partial * 100 / total_free : 0);
454 printf("Remove partial %8lu %8lu %3lu %3lu\n", 454 printf("Remove partial %8lu %8lu %3lu %3lu\n",
455 s->alloc_from_partial, s->free_remove_partial, 455 s->alloc_from_partial, s->free_remove_partial,
456 s->alloc_from_partial * 100 / total_alloc, 456 s->alloc_from_partial * 100 / total_alloc,
457 s->free_remove_partial * 100 / total_free); 457 total_free ? s->free_remove_partial * 100 / total_free : 0);
458 458
459 printf("Cpu partial list %8lu %8lu %3lu %3lu\n", 459 printf("Cpu partial list %8lu %8lu %3lu %3lu\n",
460 s->cpu_partial_alloc, s->cpu_partial_free, 460 s->cpu_partial_alloc, s->cpu_partial_free,
461 s->cpu_partial_alloc * 100 / total_alloc, 461 s->cpu_partial_alloc * 100 / total_alloc,
462 s->cpu_partial_free * 100 / total_free); 462 total_free ? s->cpu_partial_free * 100 / total_free : 0);
463 463
464 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", 464 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
465 s->deactivate_remote_frees, s->free_frozen, 465 s->deactivate_remote_frees, s->free_frozen,
466 s->deactivate_remote_frees * 100 / total_alloc, 466 s->deactivate_remote_frees * 100 / total_alloc,
467 s->free_frozen * 100 / total_free); 467 total_free ? s->free_frozen * 100 / total_free : 0);
468 468
469 printf("Total %8lu %8lu\n\n", total_alloc, total_free); 469 printf("Total %8lu %8lu\n\n", total_alloc, total_free);
470 470