diff options
Diffstat (limited to 'tools')
82 files changed, 3325 insertions, 1288 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index f759f4f097c7..fd2f9221b241 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -1299,6 +1299,7 @@ static struct device *new_device(const char *name, u16 type) | |||
1299 | dev->feature_len = 0; | 1299 | dev->feature_len = 0; |
1300 | dev->num_vq = 0; | 1300 | dev->num_vq = 0; |
1301 | dev->running = false; | 1301 | dev->running = false; |
1302 | dev->next = NULL; | ||
1302 | 1303 | ||
1303 | /* | 1304 | /* |
1304 | * Append to device list. Prepending to a single-linked list is | 1305 | * Append to device list. Prepending to a single-linked list is |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 47264b4652b9..f2989c525e48 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -2602,6 +2602,9 @@ find_func_handler(struct pevent *pevent, char *func_name) | |||
2602 | { | 2602 | { |
2603 | struct pevent_function_handler *func; | 2603 | struct pevent_function_handler *func; |
2604 | 2604 | ||
2605 | if (!pevent) | ||
2606 | return NULL; | ||
2607 | |||
2605 | for (func = pevent->func_handlers; func; func = func->next) { | 2608 | for (func = pevent->func_handlers; func; func = func->next) { |
2606 | if (strcmp(func->name, func_name) == 0) | 2609 | if (strcmp(func->name, func_name) == 0) |
2607 | break; | 2610 | break; |
@@ -4938,6 +4941,9 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
4938 | goto event_alloc_failed; | 4941 | goto event_alloc_failed; |
4939 | } | 4942 | } |
4940 | 4943 | ||
4944 | /* Add pevent to event so that it can be referenced */ | ||
4945 | event->pevent = pevent; | ||
4946 | |||
4941 | ret = event_read_format(event); | 4947 | ret = event_read_format(event); |
4942 | if (ret < 0) { | 4948 | if (ret < 0) { |
4943 | ret = PEVENT_ERRNO__READ_FORMAT_FAILED; | 4949 | ret = PEVENT_ERRNO__READ_FORMAT_FAILED; |
@@ -5041,9 +5047,6 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
5041 | if (event == NULL) | 5047 | if (event == NULL) |
5042 | return ret; | 5048 | return ret; |
5043 | 5049 | ||
5044 | /* Add pevent to event so that it can be referenced */ | ||
5045 | event->pevent = pevent; | ||
5046 | |||
5047 | if (add_event(pevent, event)) { | 5050 | if (add_event(pevent, event)) { |
5048 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | 5051 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; |
5049 | goto event_add_failed; | 5052 | goto event_add_failed; |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index ad17855528f9..5ea4326ad11f 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -209,7 +209,16 @@ static void free_arg(struct filter_arg *arg) | |||
209 | switch (arg->type) { | 209 | switch (arg->type) { |
210 | case FILTER_ARG_NONE: | 210 | case FILTER_ARG_NONE: |
211 | case FILTER_ARG_BOOLEAN: | 211 | case FILTER_ARG_BOOLEAN: |
212 | break; | ||
213 | |||
212 | case FILTER_ARG_NUM: | 214 | case FILTER_ARG_NUM: |
215 | free_arg(arg->num.left); | ||
216 | free_arg(arg->num.right); | ||
217 | break; | ||
218 | |||
219 | case FILTER_ARG_EXP: | ||
220 | free_arg(arg->exp.left); | ||
221 | free_arg(arg->exp.right); | ||
213 | break; | 222 | break; |
214 | 223 | ||
215 | case FILTER_ARG_STR: | 224 | case FILTER_ARG_STR: |
@@ -218,6 +227,12 @@ static void free_arg(struct filter_arg *arg) | |||
218 | free(arg->str.buffer); | 227 | free(arg->str.buffer); |
219 | break; | 228 | break; |
220 | 229 | ||
230 | case FILTER_ARG_VALUE: | ||
231 | if (arg->value.type == FILTER_STRING || | ||
232 | arg->value.type == FILTER_CHAR) | ||
233 | free(arg->value.str); | ||
234 | break; | ||
235 | |||
221 | case FILTER_ARG_OP: | 236 | case FILTER_ARG_OP: |
222 | free_arg(arg->op.left); | 237 | free_arg(arg->op.left); |
223 | free_arg(arg->op.right); | 238 | free_arg(arg->op.right); |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index e5e71e7d95a0..00deed4d6159 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -45,6 +45,8 @@ include config/utilities.mak | |||
45 | # | 45 | # |
46 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf | 46 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf |
47 | # backtrace post unwind. | 47 | # backtrace post unwind. |
48 | # | ||
49 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature | ||
48 | 50 | ||
49 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 51 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
50 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 52 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
@@ -72,7 +74,7 @@ ifeq ($(ARCH),x86_64) | |||
72 | override ARCH := x86 | 74 | override ARCH := x86 |
73 | IS_X86_64 := 0 | 75 | IS_X86_64 := 0 |
74 | ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) | 76 | ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) |
75 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) | 77 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) |
76 | endif | 78 | endif |
77 | ifeq (${IS_X86_64}, 1) | 79 | ifeq (${IS_X86_64}, 1) |
78 | RAW_ARCH := x86_64 | 80 | RAW_ARCH := x86_64 |
@@ -182,10 +184,23 @@ SCRIPT_SH += perf-archive.sh | |||
182 | grep-libs = $(filter -l%,$(1)) | 184 | grep-libs = $(filter -l%,$(1)) |
183 | strip-libs = $(filter-out -l%,$(1)) | 185 | strip-libs = $(filter-out -l%,$(1)) |
184 | 186 | ||
187 | TRACE_EVENT_DIR = ../lib/traceevent/ | ||
188 | |||
189 | ifneq ($(OUTPUT),) | ||
190 | TE_PATH=$(OUTPUT) | ||
191 | else | ||
192 | TE_PATH=$(TRACE_EVENT_DIR) | ||
193 | endif | ||
194 | |||
195 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | ||
196 | TE_LIB := -L$(TE_PATH) -ltraceevent | ||
197 | |||
185 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 198 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
186 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | 199 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py |
187 | 200 | ||
188 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 201 | export LIBTRACEEVENT |
202 | |||
203 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | ||
189 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 204 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
190 | --quiet build_ext; \ | 205 | --quiet build_ext; \ |
191 | mkdir -p $(OUTPUT)python && \ | 206 | mkdir -p $(OUTPUT)python && \ |
@@ -196,17 +211,6 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | |||
196 | 211 | ||
197 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) | 212 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) |
198 | 213 | ||
199 | TRACE_EVENT_DIR = ../lib/traceevent/ | ||
200 | |||
201 | ifneq ($(OUTPUT),) | ||
202 | TE_PATH=$(OUTPUT) | ||
203 | else | ||
204 | TE_PATH=$(TRACE_EVENT_DIR) | ||
205 | endif | ||
206 | |||
207 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | ||
208 | TE_LIB := -L$(TE_PATH) -ltraceevent | ||
209 | |||
210 | # | 214 | # |
211 | # Single 'perf' binary right now: | 215 | # Single 'perf' binary right now: |
212 | # | 216 | # |
@@ -250,10 +254,10 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | |||
250 | 254 | ||
251 | LIB_FILE=$(OUTPUT)libperf.a | 255 | LIB_FILE=$(OUTPUT)libperf.a |
252 | 256 | ||
253 | LIB_H += ../../include/linux/perf_event.h | 257 | LIB_H += ../../include/uapi/linux/perf_event.h |
254 | LIB_H += ../../include/linux/rbtree.h | 258 | LIB_H += ../../include/linux/rbtree.h |
255 | LIB_H += ../../include/linux/list.h | 259 | LIB_H += ../../include/linux/list.h |
256 | LIB_H += ../../include/linux/const.h | 260 | LIB_H += ../../include/uapi/linux/const.h |
257 | LIB_H += ../../include/linux/hash.h | 261 | LIB_H += ../../include/linux/hash.h |
258 | LIB_H += ../../include/linux/stringify.h | 262 | LIB_H += ../../include/linux/stringify.h |
259 | LIB_H += util/include/linux/bitmap.h | 263 | LIB_H += util/include/linux/bitmap.h |
@@ -268,6 +272,7 @@ LIB_H += util/include/linux/magic.h | |||
268 | LIB_H += util/include/linux/poison.h | 272 | LIB_H += util/include/linux/poison.h |
269 | LIB_H += util/include/linux/prefetch.h | 273 | LIB_H += util/include/linux/prefetch.h |
270 | LIB_H += util/include/linux/rbtree.h | 274 | LIB_H += util/include/linux/rbtree.h |
275 | LIB_H += util/include/linux/rbtree_augmented.h | ||
271 | LIB_H += util/include/linux/string.h | 276 | LIB_H += util/include/linux/string.h |
272 | LIB_H += util/include/linux/types.h | 277 | LIB_H += util/include/linux/types.h |
273 | LIB_H += util/include/linux/linkage.h | 278 | LIB_H += util/include/linux/linkage.h |
@@ -446,20 +451,6 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | |||
446 | 451 | ||
447 | PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) | 452 | PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) |
448 | 453 | ||
449 | # Files needed for the python binding, perf.so | ||
450 | # pyrf is just an internal name needed for all those wrappers. | ||
451 | # This has to be in sync with what is in the 'sources' variable in | ||
452 | # tools/perf/util/setup.py | ||
453 | |||
454 | PYRF_OBJS += $(OUTPUT)util/cpumap.o | ||
455 | PYRF_OBJS += $(OUTPUT)util/ctype.o | ||
456 | PYRF_OBJS += $(OUTPUT)util/evlist.o | ||
457 | PYRF_OBJS += $(OUTPUT)util/evsel.o | ||
458 | PYRF_OBJS += $(OUTPUT)util/python.o | ||
459 | PYRF_OBJS += $(OUTPUT)util/thread_map.o | ||
460 | PYRF_OBJS += $(OUTPUT)util/util.o | ||
461 | PYRF_OBJS += $(OUTPUT)util/xyarray.o | ||
462 | |||
463 | # | 454 | # |
464 | # Platform specific tweaks | 455 | # Platform specific tweaks |
465 | # | 456 | # |
@@ -486,7 +477,13 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) | |||
486 | NO_DWARF := 1 | 477 | NO_DWARF := 1 |
487 | NO_DEMANGLE := 1 | 478 | NO_DEMANGLE := 1 |
488 | endif | 479 | endif |
489 | endif | 480 | else |
481 | FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) | ||
482 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | ||
483 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | ||
484 | NO_DWARF := 1 | ||
485 | endif # Dwarf support | ||
486 | endif # SOURCE_LIBELF | ||
490 | endif # NO_LIBELF | 487 | endif # NO_LIBELF |
491 | 488 | ||
492 | ifndef NO_LIBUNWIND | 489 | ifndef NO_LIBUNWIND |
@@ -511,8 +508,6 @@ ifneq ($(OUTPUT),) | |||
511 | endif | 508 | endif |
512 | 509 | ||
513 | ifdef NO_LIBELF | 510 | ifdef NO_LIBELF |
514 | BASIC_CFLAGS += -DNO_LIBELF_SUPPORT | ||
515 | |||
516 | EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) | 511 | EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) |
517 | 512 | ||
518 | # Remove ELF/DWARF dependent codes | 513 | # Remove ELF/DWARF dependent codes |
@@ -527,17 +522,12 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) | |||
527 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o | 522 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o |
528 | 523 | ||
529 | else # NO_LIBELF | 524 | else # NO_LIBELF |
525 | BASIC_CFLAGS += -DLIBELF_SUPPORT | ||
530 | 526 | ||
531 | ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) | 527 | ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) |
532 | BASIC_CFLAGS += -DLIBELF_NO_MMAP | 528 | BASIC_CFLAGS += -DLIBELF_MMAP |
533 | endif | 529 | endif |
534 | 530 | ||
535 | FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) | ||
536 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | ||
537 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | ||
538 | NO_DWARF := 1 | ||
539 | endif # Dwarf support | ||
540 | |||
541 | ifndef NO_DWARF | 531 | ifndef NO_DWARF |
542 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 532 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
543 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 533 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
@@ -550,38 +540,33 @@ endif # PERF_HAVE_DWARF_REGS | |||
550 | endif # NO_DWARF | 540 | endif # NO_DWARF |
551 | endif # NO_LIBELF | 541 | endif # NO_LIBELF |
552 | 542 | ||
553 | ifdef NO_LIBUNWIND | 543 | ifndef NO_LIBUNWIND |
554 | BASIC_CFLAGS += -DNO_LIBUNWIND_SUPPORT | 544 | BASIC_CFLAGS += -DLIBUNWIND_SUPPORT |
555 | else | ||
556 | EXTLIBS += $(LIBUNWIND_LIBS) | 545 | EXTLIBS += $(LIBUNWIND_LIBS) |
557 | BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) | 546 | BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) |
558 | BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) | 547 | BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) |
559 | LIB_OBJS += $(OUTPUT)util/unwind.o | 548 | LIB_OBJS += $(OUTPUT)util/unwind.o |
560 | endif | 549 | endif |
561 | 550 | ||
562 | ifdef NO_LIBAUDIT | 551 | ifndef NO_LIBAUDIT |
563 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
564 | else | ||
565 | FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit | 552 | FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit |
566 | ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) | 553 | ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) |
567 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | 554 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); |
568 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
569 | else | 555 | else |
556 | BASIC_CFLAGS += -DLIBAUDIT_SUPPORT | ||
570 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | 557 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o |
571 | EXTLIBS += -laudit | 558 | EXTLIBS += -laudit |
572 | endif | 559 | endif |
573 | endif | 560 | endif |
574 | 561 | ||
575 | ifdef NO_NEWT | 562 | ifndef NO_NEWT |
576 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | ||
577 | else | ||
578 | FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt | 563 | FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt |
579 | ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) | 564 | ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) |
580 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); | 565 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); |
581 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | ||
582 | else | 566 | else |
583 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | 567 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h |
584 | BASIC_CFLAGS += -I/usr/include/slang | 568 | BASIC_CFLAGS += -I/usr/include/slang |
569 | BASIC_CFLAGS += -DNEWT_SUPPORT | ||
585 | EXTLIBS += -lnewt -lslang | 570 | EXTLIBS += -lnewt -lslang |
586 | LIB_OBJS += $(OUTPUT)ui/setup.o | 571 | LIB_OBJS += $(OUTPUT)ui/setup.o |
587 | LIB_OBJS += $(OUTPUT)ui/browser.o | 572 | LIB_OBJS += $(OUTPUT)ui/browser.o |
@@ -603,17 +588,15 @@ else | |||
603 | endif | 588 | endif |
604 | endif | 589 | endif |
605 | 590 | ||
606 | ifdef NO_GTK2 | 591 | ifndef NO_GTK2 |
607 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT | ||
608 | else | ||
609 | FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 592 | FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) |
610 | ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) | 593 | ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) |
611 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | 594 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); |
612 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT | ||
613 | else | 595 | else |
614 | ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) | 596 | ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) |
615 | BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR | 597 | BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR |
616 | endif | 598 | endif |
599 | BASIC_CFLAGS += -DGTK2_SUPPORT | ||
617 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | 600 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) |
618 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | 601 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) |
619 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | 602 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o |
@@ -621,7 +604,7 @@ else | |||
621 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | 604 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o |
622 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | 605 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o |
623 | # Make sure that it'd be included only once. | 606 | # Make sure that it'd be included only once. |
624 | ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) | 607 | ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) |
625 | LIB_OBJS += $(OUTPUT)ui/setup.o | 608 | LIB_OBJS += $(OUTPUT)ui/setup.o |
626 | LIB_OBJS += $(OUTPUT)ui/util.o | 609 | LIB_OBJS += $(OUTPUT)ui/util.o |
627 | endif | 610 | endif |
@@ -762,23 +745,18 @@ ifeq ($(NO_PERF_REGS),0) | |||
762 | ifeq ($(ARCH),x86) | 745 | ifeq ($(ARCH),x86) |
763 | LIB_H += arch/x86/include/perf_regs.h | 746 | LIB_H += arch/x86/include/perf_regs.h |
764 | endif | 747 | endif |
765 | else | 748 | BASIC_CFLAGS += -DHAVE_PERF_REGS |
766 | BASIC_CFLAGS += -DNO_PERF_REGS | ||
767 | endif | 749 | endif |
768 | 750 | ||
769 | ifdef NO_STRLCPY | 751 | ifndef NO_STRLCPY |
770 | BASIC_CFLAGS += -DNO_STRLCPY | 752 | ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y) |
771 | else | 753 | BASIC_CFLAGS += -DHAVE_STRLCPY |
772 | ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y) | ||
773 | BASIC_CFLAGS += -DNO_STRLCPY | ||
774 | endif | 754 | endif |
775 | endif | 755 | endif |
776 | 756 | ||
777 | ifdef NO_BACKTRACE | 757 | ifndef NO_BACKTRACE |
778 | BASIC_CFLAGS += -DNO_BACKTRACE | 758 | ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y) |
779 | else | 759 | BASIC_CFLAGS += -DBACKTRACE_SUPPORT |
780 | ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y) | ||
781 | BASIC_CFLAGS += -DNO_BACKTRACE | ||
782 | endif | 760 | endif |
783 | endif | 761 | endif |
784 | 762 | ||
@@ -906,7 +884,7 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | |||
906 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 884 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
907 | 885 | ||
908 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 886 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
909 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 887 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
910 | 888 | ||
911 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS | 889 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS |
912 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< | 890 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< |
diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion index 1958fa539d0f..56e6a12aab59 100644 --- a/tools/perf/bash_completion +++ b/tools/perf/bash_completion | |||
@@ -1,23 +1,59 @@ | |||
1 | # perf completion | 1 | # perf completion |
2 | 2 | ||
3 | function_exists() | ||
4 | { | ||
5 | declare -F $1 > /dev/null | ||
6 | return $? | ||
7 | } | ||
8 | |||
9 | function_exists __ltrim_colon_completions || | ||
10 | __ltrim_colon_completions() | ||
11 | { | ||
12 | if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then | ||
13 | # Remove colon-word prefix from COMPREPLY items | ||
14 | local colon_word=${1%${1##*:}} | ||
15 | local i=${#COMPREPLY[*]} | ||
16 | while [[ $((--i)) -ge 0 ]]; do | ||
17 | COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} | ||
18 | done | ||
19 | fi | ||
20 | } | ||
21 | |||
3 | have perf && | 22 | have perf && |
4 | _perf() | 23 | _perf() |
5 | { | 24 | { |
6 | local cur cmd | 25 | local cur prev cmd |
7 | 26 | ||
8 | COMPREPLY=() | 27 | COMPREPLY=() |
9 | _get_comp_words_by_ref cur prev | 28 | if function_exists _get_comp_words_by_ref; then |
29 | _get_comp_words_by_ref -n : cur prev | ||
30 | else | ||
31 | cur=$(_get_cword :) | ||
32 | prev=${COMP_WORDS[COMP_CWORD-1]} | ||
33 | fi | ||
10 | 34 | ||
11 | cmd=${COMP_WORDS[0]} | 35 | cmd=${COMP_WORDS[0]} |
12 | 36 | ||
13 | # List perf subcommands | 37 | # List perf subcommands or long options |
14 | if [ $COMP_CWORD -eq 1 ]; then | 38 | if [ $COMP_CWORD -eq 1 ]; then |
15 | cmds=$($cmd --list-cmds) | 39 | if [[ $cur == --* ]]; then |
16 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | 40 | COMPREPLY=( $( compgen -W '--help --version \ |
41 | --exec-path --html-path --paginate --no-pager \ | ||
42 | --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) | ||
43 | else | ||
44 | cmds=$($cmd --list-cmds) | ||
45 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | ||
46 | fi | ||
17 | # List possible events for -e option | 47 | # List possible events for -e option |
18 | elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then | 48 | elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then |
19 | cmds=$($cmd list --raw-dump) | 49 | evts=$($cmd list --raw-dump) |
20 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | 50 | COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) |
51 | __ltrim_colon_completions $cur | ||
52 | # List long option names | ||
53 | elif [[ $cur == --* ]]; then | ||
54 | subcmd=${COMP_WORDS[1]} | ||
55 | opts=$($cmd $subcmd --list-opts) | ||
56 | COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) | ||
21 | # Fall down to list regular files | 57 | # Fall down to list regular files |
22 | else | 58 | else |
23 | _filedir | 59 | _filedir |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 83654557e108..d37e077f4b14 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -15,22 +15,6 @@ | |||
15 | #include "util/strlist.h" | 15 | #include "util/strlist.h" |
16 | #include "util/symbol.h" | 16 | #include "util/symbol.h" |
17 | 17 | ||
18 | static char const *add_name_list_str, *remove_name_list_str; | ||
19 | |||
20 | static const char * const buildid_cache_usage[] = { | ||
21 | "perf buildid-cache [<options>]", | ||
22 | NULL | ||
23 | }; | ||
24 | |||
25 | static const struct option buildid_cache_options[] = { | ||
26 | OPT_STRING('a', "add", &add_name_list_str, | ||
27 | "file list", "file(s) to add"), | ||
28 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | ||
29 | "file(s) to remove"), | ||
30 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
31 | OPT_END() | ||
32 | }; | ||
33 | |||
34 | static int build_id_cache__add_file(const char *filename, const char *debugdir) | 18 | static int build_id_cache__add_file(const char *filename, const char *debugdir) |
35 | { | 19 | { |
36 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 20 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
@@ -51,8 +35,8 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir) | |||
51 | return err; | 35 | return err; |
52 | } | 36 | } |
53 | 37 | ||
54 | static int build_id_cache__remove_file(const char *filename __maybe_unused, | 38 | static int build_id_cache__remove_file(const char *filename, |
55 | const char *debugdir __maybe_unused) | 39 | const char *debugdir) |
56 | { | 40 | { |
57 | u8 build_id[BUILD_ID_SIZE]; | 41 | u8 build_id[BUILD_ID_SIZE]; |
58 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 42 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
@@ -73,11 +57,34 @@ static int build_id_cache__remove_file(const char *filename __maybe_unused, | |||
73 | return err; | 57 | return err; |
74 | } | 58 | } |
75 | 59 | ||
76 | static int __cmd_buildid_cache(void) | 60 | int cmd_buildid_cache(int argc, const char **argv, |
61 | const char *prefix __maybe_unused) | ||
77 | { | 62 | { |
78 | struct strlist *list; | 63 | struct strlist *list; |
79 | struct str_node *pos; | 64 | struct str_node *pos; |
80 | char debugdir[PATH_MAX]; | 65 | char debugdir[PATH_MAX]; |
66 | char const *add_name_list_str = NULL, | ||
67 | *remove_name_list_str = NULL; | ||
68 | const struct option buildid_cache_options[] = { | ||
69 | OPT_STRING('a', "add", &add_name_list_str, | ||
70 | "file list", "file(s) to add"), | ||
71 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | ||
72 | "file(s) to remove"), | ||
73 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
74 | OPT_END() | ||
75 | }; | ||
76 | const char * const buildid_cache_usage[] = { | ||
77 | "perf buildid-cache [<options>]", | ||
78 | NULL | ||
79 | }; | ||
80 | |||
81 | argc = parse_options(argc, argv, buildid_cache_options, | ||
82 | buildid_cache_usage, 0); | ||
83 | |||
84 | if (symbol__init() < 0) | ||
85 | return -1; | ||
86 | |||
87 | setup_pager(); | ||
81 | 88 | ||
82 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); | 89 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); |
83 | 90 | ||
@@ -119,16 +126,3 @@ static int __cmd_buildid_cache(void) | |||
119 | 126 | ||
120 | return 0; | 127 | return 0; |
121 | } | 128 | } |
122 | |||
123 | int cmd_buildid_cache(int argc, const char **argv, | ||
124 | const char *prefix __maybe_unused) | ||
125 | { | ||
126 | argc = parse_options(argc, argv, buildid_cache_options, | ||
127 | buildid_cache_usage, 0); | ||
128 | |||
129 | if (symbol__init() < 0) | ||
130 | return -1; | ||
131 | |||
132 | setup_pager(); | ||
133 | return __cmd_buildid_cache(); | ||
134 | } | ||
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 1159feeebb19..a0e94fffa03e 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -16,27 +16,6 @@ | |||
16 | #include "util/session.h" | 16 | #include "util/session.h" |
17 | #include "util/symbol.h" | 17 | #include "util/symbol.h" |
18 | 18 | ||
19 | static const char *input_name; | ||
20 | static bool force; | ||
21 | static bool show_kernel; | ||
22 | static bool with_hits; | ||
23 | |||
24 | static const char * const buildid_list_usage[] = { | ||
25 | "perf buildid-list [<options>]", | ||
26 | NULL | ||
27 | }; | ||
28 | |||
29 | static const struct option options[] = { | ||
30 | OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), | ||
31 | OPT_STRING('i', "input", &input_name, "file", | ||
32 | "input file name"), | ||
33 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
34 | OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), | ||
35 | OPT_INCR('v', "verbose", &verbose, | ||
36 | "be more verbose"), | ||
37 | OPT_END() | ||
38 | }; | ||
39 | |||
40 | static int sysfs__fprintf_build_id(FILE *fp) | 19 | static int sysfs__fprintf_build_id(FILE *fp) |
41 | { | 20 | { |
42 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | 21 | u8 kallsyms_build_id[BUILD_ID_SIZE]; |
@@ -65,7 +44,8 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) | |||
65 | return fprintf(fp, "%s\n", sbuild_id); | 44 | return fprintf(fp, "%s\n", sbuild_id); |
66 | } | 45 | } |
67 | 46 | ||
68 | static int perf_session__list_build_ids(void) | 47 | static int perf_session__list_build_ids(const char *input_name, |
48 | bool force, bool with_hits) | ||
69 | { | 49 | { |
70 | struct perf_session *session; | 50 | struct perf_session *session; |
71 | 51 | ||
@@ -95,18 +75,31 @@ out: | |||
95 | return 0; | 75 | return 0; |
96 | } | 76 | } |
97 | 77 | ||
98 | static int __cmd_buildid_list(void) | ||
99 | { | ||
100 | if (show_kernel) | ||
101 | return sysfs__fprintf_build_id(stdout); | ||
102 | |||
103 | return perf_session__list_build_ids(); | ||
104 | } | ||
105 | |||
106 | int cmd_buildid_list(int argc, const char **argv, | 78 | int cmd_buildid_list(int argc, const char **argv, |
107 | const char *prefix __maybe_unused) | 79 | const char *prefix __maybe_unused) |
108 | { | 80 | { |
81 | bool show_kernel = false; | ||
82 | bool with_hits = false; | ||
83 | bool force = false; | ||
84 | const char *input_name = NULL; | ||
85 | const struct option options[] = { | ||
86 | OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), | ||
87 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
88 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
89 | OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), | ||
90 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
91 | OPT_END() | ||
92 | }; | ||
93 | const char * const buildid_list_usage[] = { | ||
94 | "perf buildid-list [<options>]", | ||
95 | NULL | ||
96 | }; | ||
97 | |||
109 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); | 98 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); |
110 | setup_pager(); | 99 | setup_pager(); |
111 | return __cmd_buildid_list(); | 100 | |
101 | if (show_kernel) | ||
102 | return sysfs__fprintf_build_id(stdout); | ||
103 | |||
104 | return perf_session__list_build_ids(input_name, force, with_hits); | ||
112 | } | 105 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 761f4197a9e2..a0b531c14b97 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -70,8 +70,8 @@ static struct perf_tool tool = { | |||
70 | .ordering_requires_timestamps = true, | 70 | .ordering_requires_timestamps = true, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static void perf_session__insert_hist_entry_by_name(struct rb_root *root, | 73 | static void insert_hist_entry_by_name(struct rb_root *root, |
74 | struct hist_entry *he) | 74 | struct hist_entry *he) |
75 | { | 75 | { |
76 | struct rb_node **p = &root->rb_node; | 76 | struct rb_node **p = &root->rb_node; |
77 | struct rb_node *parent = NULL; | 77 | struct rb_node *parent = NULL; |
@@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root, | |||
90 | rb_insert_color(&he->rb_node, root); | 90 | rb_insert_color(&he->rb_node, root); |
91 | } | 91 | } |
92 | 92 | ||
93 | static void hists__resort_entries(struct hists *self) | 93 | static void hists__name_resort(struct hists *self, bool sort) |
94 | { | 94 | { |
95 | unsigned long position = 1; | 95 | unsigned long position = 1; |
96 | struct rb_root tmp = RB_ROOT; | 96 | struct rb_root tmp = RB_ROOT; |
@@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self) | |||
100 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); | 100 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); |
101 | 101 | ||
102 | next = rb_next(&n->rb_node); | 102 | next = rb_next(&n->rb_node); |
103 | rb_erase(&n->rb_node, &self->entries); | ||
104 | n->position = position++; | 103 | n->position = position++; |
105 | perf_session__insert_hist_entry_by_name(&tmp, n); | 104 | |
105 | if (sort) { | ||
106 | rb_erase(&n->rb_node, &self->entries); | ||
107 | insert_hist_entry_by_name(&tmp, n); | ||
108 | } | ||
106 | } | 109 | } |
107 | 110 | ||
108 | self->entries = tmp; | 111 | if (sort) |
112 | self->entries = tmp; | ||
109 | } | 113 | } |
110 | 114 | ||
111 | static struct hist_entry *hists__find_entry(struct hists *self, | 115 | static struct hist_entry *hists__find_entry(struct hists *self, |
@@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self, | |||
121 | n = n->rb_left; | 125 | n = n->rb_left; |
122 | else if (cmp > 0) | 126 | else if (cmp > 0) |
123 | n = n->rb_right; | 127 | n = n->rb_right; |
124 | else | 128 | else |
125 | return iter; | 129 | return iter; |
126 | } | 130 | } |
127 | 131 | ||
@@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | |||
150 | return NULL; | 154 | return NULL; |
151 | } | 155 | } |
152 | 156 | ||
157 | static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) | ||
158 | { | ||
159 | struct perf_evsel *evsel; | ||
160 | |||
161 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
162 | struct hists *hists = &evsel->hists; | ||
163 | |||
164 | hists__output_resort(hists); | ||
165 | |||
166 | /* | ||
167 | * The hists__name_resort only sets possition | ||
168 | * if name is false. | ||
169 | */ | ||
170 | if (name || ((!name) && show_displacement)) | ||
171 | hists__name_resort(hists, name); | ||
172 | } | ||
173 | } | ||
174 | |||
153 | static int __cmd_diff(void) | 175 | static int __cmd_diff(void) |
154 | { | 176 | { |
155 | int ret, i; | 177 | int ret, i; |
@@ -176,15 +198,8 @@ static int __cmd_diff(void) | |||
176 | evlist_old = older->evlist; | 198 | evlist_old = older->evlist; |
177 | evlist_new = newer->evlist; | 199 | evlist_new = newer->evlist; |
178 | 200 | ||
179 | list_for_each_entry(evsel, &evlist_new->entries, node) | 201 | perf_evlist__resort_hists(evlist_old, true); |
180 | hists__output_resort(&evsel->hists); | 202 | perf_evlist__resort_hists(evlist_new, false); |
181 | |||
182 | list_for_each_entry(evsel, &evlist_old->entries, node) { | ||
183 | hists__output_resort(&evsel->hists); | ||
184 | |||
185 | if (show_displacement) | ||
186 | hists__resort_entries(&evsel->hists); | ||
187 | } | ||
188 | 203 | ||
189 | list_for_each_entry(evsel, &evlist_new->entries, node) { | 204 | list_for_each_entry(evsel, &evlist_new->entries, node) { |
190 | struct perf_evsel *evsel_old; | 205 | struct perf_evsel *evsel_old; |
@@ -199,8 +214,7 @@ static int __cmd_diff(void) | |||
199 | first = false; | 214 | first = false; |
200 | 215 | ||
201 | hists__match(&evsel_old->hists, &evsel->hists); | 216 | hists__match(&evsel_old->hists, &evsel->hists); |
202 | hists__fprintf(&evsel->hists, &evsel_old->hists, | 217 | hists__fprintf(&evsel->hists, true, 0, 0, stdout); |
203 | show_displacement, true, 0, 0, stdout); | ||
204 | } | 218 | } |
205 | 219 | ||
206 | out_delete: | 220 | out_delete: |
@@ -242,6 +256,21 @@ static const struct option options[] = { | |||
242 | OPT_END() | 256 | OPT_END() |
243 | }; | 257 | }; |
244 | 258 | ||
259 | static void ui_init(void) | ||
260 | { | ||
261 | perf_hpp__init(); | ||
262 | |||
263 | /* No overhead column. */ | ||
264 | perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); | ||
265 | |||
266 | /* Display baseline/delta/displacement columns. */ | ||
267 | perf_hpp__column_enable(PERF_HPP__BASELINE, true); | ||
268 | perf_hpp__column_enable(PERF_HPP__DELTA, true); | ||
269 | |||
270 | if (show_displacement) | ||
271 | perf_hpp__column_enable(PERF_HPP__DISPL, true); | ||
272 | } | ||
273 | |||
245 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | 274 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) |
246 | { | 275 | { |
247 | sort_order = diff__default_sort_order; | 276 | sort_order = diff__default_sort_order; |
@@ -264,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
264 | if (symbol__init() < 0) | 293 | if (symbol__init() < 0) |
265 | return -1; | 294 | return -1; |
266 | 295 | ||
267 | perf_hpp__init(true, show_displacement); | 296 | ui_init(); |
297 | |||
268 | setup_sorting(diff_usage, options); | 298 | setup_sorting(diff_usage, options); |
269 | setup_pager(); | 299 | setup_pager(); |
270 | 300 | ||
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 1fb164164fd0..997afb82691b 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -108,23 +108,20 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail | |||
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | static const char * const evlist_usage[] = { | ||
112 | "perf evlist [<options>]", | ||
113 | NULL | ||
114 | }; | ||
115 | |||
116 | int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | 111 | int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) |
117 | { | 112 | { |
118 | struct perf_attr_details details = { .verbose = false, }; | 113 | struct perf_attr_details details = { .verbose = false, }; |
119 | const char *input_name = NULL; | 114 | const char *input_name = NULL; |
120 | const struct option options[] = { | 115 | const struct option options[] = { |
121 | OPT_STRING('i', "input", &input_name, "file", | 116 | OPT_STRING('i', "input", &input_name, "file", "Input file name"), |
122 | "Input file name"), | 117 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), |
123 | OPT_BOOLEAN('F', "freq", &details.freq, | 118 | OPT_BOOLEAN('v', "verbose", &details.verbose, |
124 | "Show the sample frequency"), | 119 | "Show all event attr details"), |
125 | OPT_BOOLEAN('v', "verbose", &details.verbose, | 120 | OPT_END() |
126 | "Show all event attr details"), | 121 | }; |
127 | OPT_END() | 122 | const char * const evlist_usage[] = { |
123 | "perf evlist [<options>]", | ||
124 | NULL | ||
128 | }; | 125 | }; |
129 | 126 | ||
130 | argc = parse_options(argc, argv, options, evlist_usage, 0); | 127 | argc = parse_options(argc, argv, options, evlist_usage, 0); |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 25c8b942ff85..178b88ae3d2f 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -30,23 +30,6 @@ enum help_format { | |||
30 | HELP_FORMAT_WEB, | 30 | HELP_FORMAT_WEB, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | static bool show_all = false; | ||
34 | static enum help_format help_format = HELP_FORMAT_NONE; | ||
35 | static struct option builtin_help_options[] = { | ||
36 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), | ||
37 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), | ||
38 | OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", | ||
39 | HELP_FORMAT_WEB), | ||
40 | OPT_SET_UINT('i', "info", &help_format, "show info page", | ||
41 | HELP_FORMAT_INFO), | ||
42 | OPT_END(), | ||
43 | }; | ||
44 | |||
45 | static const char * const builtin_help_usage[] = { | ||
46 | "perf help [--all] [--man|--web|--info] [command]", | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | static enum help_format parse_help_format(const char *format) | 33 | static enum help_format parse_help_format(const char *format) |
51 | { | 34 | { |
52 | if (!strcmp(format, "man")) | 35 | if (!strcmp(format, "man")) |
@@ -258,11 +241,13 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
258 | 241 | ||
259 | static int perf_help_config(const char *var, const char *value, void *cb) | 242 | static int perf_help_config(const char *var, const char *value, void *cb) |
260 | { | 243 | { |
244 | enum help_format *help_formatp = cb; | ||
245 | |||
261 | if (!strcmp(var, "help.format")) { | 246 | if (!strcmp(var, "help.format")) { |
262 | if (!value) | 247 | if (!value) |
263 | return config_error_nonbool(var); | 248 | return config_error_nonbool(var); |
264 | help_format = parse_help_format(value); | 249 | *help_formatp = parse_help_format(value); |
265 | if (help_format == HELP_FORMAT_NONE) | 250 | if (*help_formatp == HELP_FORMAT_NONE) |
266 | return -1; | 251 | return -1; |
267 | return 0; | 252 | return 0; |
268 | } | 253 | } |
@@ -428,12 +413,27 @@ static int show_html_page(const char *perf_cmd) | |||
428 | 413 | ||
429 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) | 414 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) |
430 | { | 415 | { |
416 | bool show_all = false; | ||
417 | enum help_format help_format = HELP_FORMAT_MAN; | ||
418 | struct option builtin_help_options[] = { | ||
419 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), | ||
420 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), | ||
421 | OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", | ||
422 | HELP_FORMAT_WEB), | ||
423 | OPT_SET_UINT('i', "info", &help_format, "show info page", | ||
424 | HELP_FORMAT_INFO), | ||
425 | OPT_END(), | ||
426 | }; | ||
427 | const char * const builtin_help_usage[] = { | ||
428 | "perf help [--all] [--man|--web|--info] [command]", | ||
429 | NULL | ||
430 | }; | ||
431 | const char *alias; | 431 | const char *alias; |
432 | int rc = 0; | 432 | int rc = 0; |
433 | 433 | ||
434 | load_command_list("perf-", &main_cmds, &other_cmds); | 434 | load_command_list("perf-", &main_cmds, &other_cmds); |
435 | 435 | ||
436 | perf_config(perf_help_config, NULL); | 436 | perf_config(perf_help_config, &help_format); |
437 | 437 | ||
438 | argc = parse_options(argc, argv, builtin_help_options, | 438 | argc = parse_options(argc, argv, builtin_help_options, |
439 | builtin_help_usage, 0); | 439 | builtin_help_usage, 0); |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 1eaa6617c814..4688bea95c12 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -14,8 +14,10 @@ | |||
14 | 14 | ||
15 | #include "util/parse-options.h" | 15 | #include "util/parse-options.h" |
16 | 16 | ||
17 | static char const *input_name = "-"; | 17 | struct perf_inject { |
18 | static bool inject_build_ids; | 18 | struct perf_tool tool; |
19 | bool build_ids; | ||
20 | }; | ||
19 | 21 | ||
20 | static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, | 22 | static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, |
21 | union perf_event *event, | 23 | union perf_event *event, |
@@ -194,7 +196,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, | |||
194 | * account this as unresolved. | 196 | * account this as unresolved. |
195 | */ | 197 | */ |
196 | } else { | 198 | } else { |
197 | #ifndef NO_LIBELF_SUPPORT | 199 | #ifdef LIBELF_SUPPORT |
198 | pr_warning("no symbols found in %s, maybe " | 200 | pr_warning("no symbols found in %s, maybe " |
199 | "install a debug package?\n", | 201 | "install a debug package?\n", |
200 | al.map->dso->long_name); | 202 | al.map->dso->long_name); |
@@ -208,22 +210,6 @@ repipe: | |||
208 | return 0; | 210 | return 0; |
209 | } | 211 | } |
210 | 212 | ||
211 | struct perf_tool perf_inject = { | ||
212 | .sample = perf_event__repipe_sample, | ||
213 | .mmap = perf_event__repipe, | ||
214 | .comm = perf_event__repipe, | ||
215 | .fork = perf_event__repipe, | ||
216 | .exit = perf_event__repipe, | ||
217 | .lost = perf_event__repipe, | ||
218 | .read = perf_event__repipe_sample, | ||
219 | .throttle = perf_event__repipe, | ||
220 | .unthrottle = perf_event__repipe, | ||
221 | .attr = perf_event__repipe_attr, | ||
222 | .event_type = perf_event__repipe_event_type_synth, | ||
223 | .tracing_data = perf_event__repipe_tracing_data_synth, | ||
224 | .build_id = perf_event__repipe_op2_synth, | ||
225 | }; | ||
226 | |||
227 | extern volatile int session_done; | 213 | extern volatile int session_done; |
228 | 214 | ||
229 | static void sig_handler(int sig __maybe_unused) | 215 | static void sig_handler(int sig __maybe_unused) |
@@ -231,56 +217,72 @@ static void sig_handler(int sig __maybe_unused) | |||
231 | session_done = 1; | 217 | session_done = 1; |
232 | } | 218 | } |
233 | 219 | ||
234 | static int __cmd_inject(void) | 220 | static int __cmd_inject(struct perf_inject *inject) |
235 | { | 221 | { |
236 | struct perf_session *session; | 222 | struct perf_session *session; |
237 | int ret = -EINVAL; | 223 | int ret = -EINVAL; |
238 | 224 | ||
239 | signal(SIGINT, sig_handler); | 225 | signal(SIGINT, sig_handler); |
240 | 226 | ||
241 | if (inject_build_ids) { | 227 | if (inject->build_ids) { |
242 | perf_inject.sample = perf_event__inject_buildid; | 228 | inject->tool.sample = perf_event__inject_buildid; |
243 | perf_inject.mmap = perf_event__repipe_mmap; | 229 | inject->tool.mmap = perf_event__repipe_mmap; |
244 | perf_inject.fork = perf_event__repipe_task; | 230 | inject->tool.fork = perf_event__repipe_task; |
245 | perf_inject.tracing_data = perf_event__repipe_tracing_data; | 231 | inject->tool.tracing_data = perf_event__repipe_tracing_data; |
246 | } | 232 | } |
247 | 233 | ||
248 | session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); | 234 | session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); |
249 | if (session == NULL) | 235 | if (session == NULL) |
250 | return -ENOMEM; | 236 | return -ENOMEM; |
251 | 237 | ||
252 | ret = perf_session__process_events(session, &perf_inject); | 238 | ret = perf_session__process_events(session, &inject->tool); |
253 | 239 | ||
254 | perf_session__delete(session); | 240 | perf_session__delete(session); |
255 | 241 | ||
256 | return ret; | 242 | return ret; |
257 | } | 243 | } |
258 | 244 | ||
259 | static const char * const report_usage[] = { | ||
260 | "perf inject [<options>]", | ||
261 | NULL | ||
262 | }; | ||
263 | |||
264 | static const struct option options[] = { | ||
265 | OPT_BOOLEAN('b', "build-ids", &inject_build_ids, | ||
266 | "Inject build-ids into the output stream"), | ||
267 | OPT_INCR('v', "verbose", &verbose, | ||
268 | "be more verbose (show build ids, etc)"), | ||
269 | OPT_END() | ||
270 | }; | ||
271 | |||
272 | int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | 245 | int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) |
273 | { | 246 | { |
274 | argc = parse_options(argc, argv, options, report_usage, 0); | 247 | struct perf_inject inject = { |
248 | .tool = { | ||
249 | .sample = perf_event__repipe_sample, | ||
250 | .mmap = perf_event__repipe, | ||
251 | .comm = perf_event__repipe, | ||
252 | .fork = perf_event__repipe, | ||
253 | .exit = perf_event__repipe, | ||
254 | .lost = perf_event__repipe, | ||
255 | .read = perf_event__repipe_sample, | ||
256 | .throttle = perf_event__repipe, | ||
257 | .unthrottle = perf_event__repipe, | ||
258 | .attr = perf_event__repipe_attr, | ||
259 | .event_type = perf_event__repipe_event_type_synth, | ||
260 | .tracing_data = perf_event__repipe_tracing_data_synth, | ||
261 | .build_id = perf_event__repipe_op2_synth, | ||
262 | }, | ||
263 | }; | ||
264 | const struct option options[] = { | ||
265 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, | ||
266 | "Inject build-ids into the output stream"), | ||
267 | OPT_INCR('v', "verbose", &verbose, | ||
268 | "be more verbose (show build ids, etc)"), | ||
269 | OPT_END() | ||
270 | }; | ||
271 | const char * const inject_usage[] = { | ||
272 | "perf inject [<options>]", | ||
273 | NULL | ||
274 | }; | ||
275 | |||
276 | argc = parse_options(argc, argv, options, inject_usage, 0); | ||
275 | 277 | ||
276 | /* | 278 | /* |
277 | * Any (unrecognized) arguments left? | 279 | * Any (unrecognized) arguments left? |
278 | */ | 280 | */ |
279 | if (argc) | 281 | if (argc) |
280 | usage_with_options(report_usage, options); | 282 | usage_with_options(inject_usage, options); |
281 | 283 | ||
282 | if (symbol__init() < 0) | 284 | if (symbol__init() < 0) |
283 | return -1; | 285 | return -1; |
284 | 286 | ||
285 | return __cmd_inject(); | 287 | return __cmd_inject(&inject); |
286 | } | 288 | } |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index bc912c68f49a..14bf82f63659 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -21,8 +21,6 @@ | |||
21 | struct alloc_stat; | 21 | struct alloc_stat; |
22 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); | 22 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); |
23 | 23 | ||
24 | static const char *input_name; | ||
25 | |||
26 | static int alloc_flag; | 24 | static int alloc_flag; |
27 | static int caller_flag; | 25 | static int caller_flag; |
28 | 26 | ||
@@ -31,8 +29,6 @@ static int caller_lines = -1; | |||
31 | 29 | ||
32 | static bool raw_ip; | 30 | static bool raw_ip; |
33 | 31 | ||
34 | static char default_sort_order[] = "frag,hit,bytes"; | ||
35 | |||
36 | static int *cpunode_map; | 32 | static int *cpunode_map; |
37 | static int max_cpu_num; | 33 | static int max_cpu_num; |
38 | 34 | ||
@@ -481,7 +477,7 @@ static void sort_result(void) | |||
481 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); | 477 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); |
482 | } | 478 | } |
483 | 479 | ||
484 | static int __cmd_kmem(void) | 480 | static int __cmd_kmem(const char *input_name) |
485 | { | 481 | { |
486 | int err = -EINVAL; | 482 | int err = -EINVAL; |
487 | struct perf_session *session; | 483 | struct perf_session *session; |
@@ -520,11 +516,6 @@ out_delete: | |||
520 | return err; | 516 | return err; |
521 | } | 517 | } |
522 | 518 | ||
523 | static const char * const kmem_usage[] = { | ||
524 | "perf kmem [<options>] {record|stat}", | ||
525 | NULL | ||
526 | }; | ||
527 | |||
528 | static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) | 519 | static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) |
529 | { | 520 | { |
530 | if (l->ptr < r->ptr) | 521 | if (l->ptr < r->ptr) |
@@ -720,41 +711,17 @@ static int parse_line_opt(const struct option *opt __maybe_unused, | |||
720 | return 0; | 711 | return 0; |
721 | } | 712 | } |
722 | 713 | ||
723 | static const struct option kmem_options[] = { | 714 | static int __cmd_record(int argc, const char **argv) |
724 | OPT_STRING('i', "input", &input_name, "file", | 715 | { |
725 | "input file name"), | 716 | const char * const record_args[] = { |
726 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, | 717 | "record", "-a", "-R", "-f", "-c", "1", |
727 | "show per-callsite statistics", | ||
728 | parse_caller_opt), | ||
729 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
730 | "show per-allocation statistics", | ||
731 | parse_alloc_opt), | ||
732 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | ||
733 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | ||
734 | parse_sort_opt), | ||
735 | OPT_CALLBACK('l', "line", NULL, "num", | ||
736 | "show n lines", | ||
737 | parse_line_opt), | ||
738 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | ||
739 | OPT_END() | ||
740 | }; | ||
741 | |||
742 | static const char *record_args[] = { | ||
743 | "record", | ||
744 | "-a", | ||
745 | "-R", | ||
746 | "-f", | ||
747 | "-c", "1", | ||
748 | "-e", "kmem:kmalloc", | 718 | "-e", "kmem:kmalloc", |
749 | "-e", "kmem:kmalloc_node", | 719 | "-e", "kmem:kmalloc_node", |
750 | "-e", "kmem:kfree", | 720 | "-e", "kmem:kfree", |
751 | "-e", "kmem:kmem_cache_alloc", | 721 | "-e", "kmem:kmem_cache_alloc", |
752 | "-e", "kmem:kmem_cache_alloc_node", | 722 | "-e", "kmem:kmem_cache_alloc_node", |
753 | "-e", "kmem:kmem_cache_free", | 723 | "-e", "kmem:kmem_cache_free", |
754 | }; | 724 | }; |
755 | |||
756 | static int __cmd_record(int argc, const char **argv) | ||
757 | { | ||
758 | unsigned int rec_argc, i, j; | 725 | unsigned int rec_argc, i, j; |
759 | const char **rec_argv; | 726 | const char **rec_argv; |
760 | 727 | ||
@@ -775,6 +742,25 @@ static int __cmd_record(int argc, const char **argv) | |||
775 | 742 | ||
776 | int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | 743 | int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) |
777 | { | 744 | { |
745 | const char * const default_sort_order = "frag,hit,bytes"; | ||
746 | const char *input_name = NULL; | ||
747 | const struct option kmem_options[] = { | ||
748 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
749 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, | ||
750 | "show per-callsite statistics", parse_caller_opt), | ||
751 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
752 | "show per-allocation statistics", parse_alloc_opt), | ||
753 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | ||
754 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | ||
755 | parse_sort_opt), | ||
756 | OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), | ||
757 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | ||
758 | OPT_END() | ||
759 | }; | ||
760 | const char * const kmem_usage[] = { | ||
761 | "perf kmem [<options>] {record|stat}", | ||
762 | NULL | ||
763 | }; | ||
778 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); | 764 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); |
779 | 765 | ||
780 | if (!argc) | 766 | if (!argc) |
@@ -793,7 +779,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
793 | if (list_empty(&alloc_sort)) | 779 | if (list_empty(&alloc_sort)) |
794 | setup_sorting(&alloc_sort, default_sort_order); | 780 | setup_sorting(&alloc_sort, default_sort_order); |
795 | 781 | ||
796 | return __cmd_kmem(); | 782 | return __cmd_kmem(input_name); |
797 | } else | 783 | } else |
798 | usage_with_options(kmem_usage, kmem_options); | 784 | usage_with_options(kmem_usage, kmem_options); |
799 | 785 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index a28c9cad9048..260abc535b5b 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -32,16 +32,76 @@ struct event_key { | |||
32 | int info; | 32 | int info; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | struct kvm_event_stats { | ||
36 | u64 time; | ||
37 | struct stats stats; | ||
38 | }; | ||
39 | |||
40 | struct kvm_event { | ||
41 | struct list_head hash_entry; | ||
42 | struct rb_node rb; | ||
43 | |||
44 | struct event_key key; | ||
45 | |||
46 | struct kvm_event_stats total; | ||
47 | |||
48 | #define DEFAULT_VCPU_NUM 8 | ||
49 | int max_vcpu; | ||
50 | struct kvm_event_stats *vcpu; | ||
51 | }; | ||
52 | |||
53 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
54 | |||
55 | struct kvm_event_key { | ||
56 | const char *name; | ||
57 | key_cmp_fun key; | ||
58 | }; | ||
59 | |||
60 | |||
61 | struct perf_kvm; | ||
62 | |||
35 | struct kvm_events_ops { | 63 | struct kvm_events_ops { |
36 | bool (*is_begin_event)(struct perf_evsel *evsel, | 64 | bool (*is_begin_event)(struct perf_evsel *evsel, |
37 | struct perf_sample *sample, | 65 | struct perf_sample *sample, |
38 | struct event_key *key); | 66 | struct event_key *key); |
39 | bool (*is_end_event)(struct perf_evsel *evsel, | 67 | bool (*is_end_event)(struct perf_evsel *evsel, |
40 | struct perf_sample *sample, struct event_key *key); | 68 | struct perf_sample *sample, struct event_key *key); |
41 | void (*decode_key)(struct event_key *key, char decode[20]); | 69 | void (*decode_key)(struct perf_kvm *kvm, struct event_key *key, |
70 | char decode[20]); | ||
42 | const char *name; | 71 | const char *name; |
43 | }; | 72 | }; |
44 | 73 | ||
74 | struct exit_reasons_table { | ||
75 | unsigned long exit_code; | ||
76 | const char *reason; | ||
77 | }; | ||
78 | |||
79 | #define EVENTS_BITS 12 | ||
80 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
81 | |||
82 | struct perf_kvm { | ||
83 | struct perf_tool tool; | ||
84 | struct perf_session *session; | ||
85 | |||
86 | const char *file_name; | ||
87 | const char *report_event; | ||
88 | const char *sort_key; | ||
89 | int trace_vcpu; | ||
90 | |||
91 | struct exit_reasons_table *exit_reasons; | ||
92 | int exit_reasons_size; | ||
93 | const char *exit_reasons_isa; | ||
94 | |||
95 | struct kvm_events_ops *events_ops; | ||
96 | key_cmp_fun compare; | ||
97 | struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
98 | u64 total_time; | ||
99 | u64 total_count; | ||
100 | |||
101 | struct rb_root result; | ||
102 | }; | ||
103 | |||
104 | |||
45 | static void exit_event_get_key(struct perf_evsel *evsel, | 105 | static void exit_event_get_key(struct perf_evsel *evsel, |
46 | struct perf_sample *sample, | 106 | struct perf_sample *sample, |
47 | struct event_key *key) | 107 | struct event_key *key) |
@@ -78,45 +138,35 @@ static bool exit_event_end(struct perf_evsel *evsel, | |||
78 | return kvm_entry_event(evsel); | 138 | return kvm_entry_event(evsel); |
79 | } | 139 | } |
80 | 140 | ||
81 | struct exit_reasons_table { | 141 | static struct exit_reasons_table vmx_exit_reasons[] = { |
82 | unsigned long exit_code; | ||
83 | const char *reason; | ||
84 | }; | ||
85 | |||
86 | struct exit_reasons_table vmx_exit_reasons[] = { | ||
87 | VMX_EXIT_REASONS | 142 | VMX_EXIT_REASONS |
88 | }; | 143 | }; |
89 | 144 | ||
90 | struct exit_reasons_table svm_exit_reasons[] = { | 145 | static struct exit_reasons_table svm_exit_reasons[] = { |
91 | SVM_EXIT_REASONS | 146 | SVM_EXIT_REASONS |
92 | }; | 147 | }; |
93 | 148 | ||
94 | static int cpu_isa; | 149 | static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code) |
95 | |||
96 | static const char *get_exit_reason(u64 exit_code) | ||
97 | { | 150 | { |
98 | int table_size = ARRAY_SIZE(svm_exit_reasons); | 151 | int i = kvm->exit_reasons_size; |
99 | struct exit_reasons_table *table = svm_exit_reasons; | 152 | struct exit_reasons_table *tbl = kvm->exit_reasons; |
100 | |||
101 | if (cpu_isa == 1) { | ||
102 | table = vmx_exit_reasons; | ||
103 | table_size = ARRAY_SIZE(vmx_exit_reasons); | ||
104 | } | ||
105 | 153 | ||
106 | while (table_size--) { | 154 | while (i--) { |
107 | if (table->exit_code == exit_code) | 155 | if (tbl->exit_code == exit_code) |
108 | return table->reason; | 156 | return tbl->reason; |
109 | table++; | 157 | tbl++; |
110 | } | 158 | } |
111 | 159 | ||
112 | pr_err("unknown kvm exit code:%lld on %s\n", | 160 | pr_err("unknown kvm exit code:%lld on %s\n", |
113 | (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); | 161 | (unsigned long long)exit_code, kvm->exit_reasons_isa); |
114 | return "UNKNOWN"; | 162 | return "UNKNOWN"; |
115 | } | 163 | } |
116 | 164 | ||
117 | static void exit_event_decode_key(struct event_key *key, char decode[20]) | 165 | static void exit_event_decode_key(struct perf_kvm *kvm, |
166 | struct event_key *key, | ||
167 | char decode[20]) | ||
118 | { | 168 | { |
119 | const char *exit_reason = get_exit_reason(key->key); | 169 | const char *exit_reason = get_exit_reason(kvm, key->key); |
120 | 170 | ||
121 | scnprintf(decode, 20, "%s", exit_reason); | 171 | scnprintf(decode, 20, "%s", exit_reason); |
122 | } | 172 | } |
@@ -128,11 +178,11 @@ static struct kvm_events_ops exit_events = { | |||
128 | .name = "VM-EXIT" | 178 | .name = "VM-EXIT" |
129 | }; | 179 | }; |
130 | 180 | ||
131 | /* | 181 | /* |
132 | * For the mmio events, we treat: | 182 | * For the mmio events, we treat: |
133 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry | 183 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry |
134 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). | 184 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). |
135 | */ | 185 | */ |
136 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, | 186 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, |
137 | struct event_key *key) | 187 | struct event_key *key) |
138 | { | 188 | { |
@@ -178,7 +228,9 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, | |||
178 | return false; | 228 | return false; |
179 | } | 229 | } |
180 | 230 | ||
181 | static void mmio_event_decode_key(struct event_key *key, char decode[20]) | 231 | static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused, |
232 | struct event_key *key, | ||
233 | char decode[20]) | ||
182 | { | 234 | { |
183 | scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, | 235 | scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, |
184 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); | 236 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); |
@@ -219,7 +271,9 @@ static bool ioport_event_end(struct perf_evsel *evsel, | |||
219 | return kvm_entry_event(evsel); | 271 | return kvm_entry_event(evsel); |
220 | } | 272 | } |
221 | 273 | ||
222 | static void ioport_event_decode_key(struct event_key *key, char decode[20]) | 274 | static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused, |
275 | struct event_key *key, | ||
276 | char decode[20]) | ||
223 | { | 277 | { |
224 | scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, | 278 | scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, |
225 | key->info ? "POUT" : "PIN"); | 279 | key->info ? "POUT" : "PIN"); |
@@ -232,64 +286,37 @@ static struct kvm_events_ops ioport_events = { | |||
232 | .name = "IO Port Access" | 286 | .name = "IO Port Access" |
233 | }; | 287 | }; |
234 | 288 | ||
235 | static const char *report_event = "vmexit"; | 289 | static bool register_kvm_events_ops(struct perf_kvm *kvm) |
236 | struct kvm_events_ops *events_ops; | ||
237 | |||
238 | static bool register_kvm_events_ops(void) | ||
239 | { | 290 | { |
240 | bool ret = true; | 291 | bool ret = true; |
241 | 292 | ||
242 | if (!strcmp(report_event, "vmexit")) | 293 | if (!strcmp(kvm->report_event, "vmexit")) |
243 | events_ops = &exit_events; | 294 | kvm->events_ops = &exit_events; |
244 | else if (!strcmp(report_event, "mmio")) | 295 | else if (!strcmp(kvm->report_event, "mmio")) |
245 | events_ops = &mmio_events; | 296 | kvm->events_ops = &mmio_events; |
246 | else if (!strcmp(report_event, "ioport")) | 297 | else if (!strcmp(kvm->report_event, "ioport")) |
247 | events_ops = &ioport_events; | 298 | kvm->events_ops = &ioport_events; |
248 | else { | 299 | else { |
249 | pr_err("Unknown report event:%s\n", report_event); | 300 | pr_err("Unknown report event:%s\n", kvm->report_event); |
250 | ret = false; | 301 | ret = false; |
251 | } | 302 | } |
252 | 303 | ||
253 | return ret; | 304 | return ret; |
254 | } | 305 | } |
255 | 306 | ||
256 | struct kvm_event_stats { | ||
257 | u64 time; | ||
258 | struct stats stats; | ||
259 | }; | ||
260 | |||
261 | struct kvm_event { | ||
262 | struct list_head hash_entry; | ||
263 | struct rb_node rb; | ||
264 | |||
265 | struct event_key key; | ||
266 | |||
267 | struct kvm_event_stats total; | ||
268 | |||
269 | #define DEFAULT_VCPU_NUM 8 | ||
270 | int max_vcpu; | ||
271 | struct kvm_event_stats *vcpu; | ||
272 | }; | ||
273 | |||
274 | struct vcpu_event_record { | 307 | struct vcpu_event_record { |
275 | int vcpu_id; | 308 | int vcpu_id; |
276 | u64 start_time; | 309 | u64 start_time; |
277 | struct kvm_event *last_event; | 310 | struct kvm_event *last_event; |
278 | }; | 311 | }; |
279 | 312 | ||
280 | #define EVENTS_BITS 12 | ||
281 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
282 | |||
283 | static u64 total_time; | ||
284 | static u64 total_count; | ||
285 | static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
286 | 313 | ||
287 | static void init_kvm_event_record(void) | 314 | static void init_kvm_event_record(struct perf_kvm *kvm) |
288 | { | 315 | { |
289 | int i; | 316 | int i; |
290 | 317 | ||
291 | for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) | 318 | for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) |
292 | INIT_LIST_HEAD(&kvm_events_cache[i]); | 319 | INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); |
293 | } | 320 | } |
294 | 321 | ||
295 | static int kvm_events_hash_fn(u64 key) | 322 | static int kvm_events_hash_fn(u64 key) |
@@ -333,14 +360,15 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key) | |||
333 | return event; | 360 | return event; |
334 | } | 361 | } |
335 | 362 | ||
336 | static struct kvm_event *find_create_kvm_event(struct event_key *key) | 363 | static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm, |
364 | struct event_key *key) | ||
337 | { | 365 | { |
338 | struct kvm_event *event; | 366 | struct kvm_event *event; |
339 | struct list_head *head; | 367 | struct list_head *head; |
340 | 368 | ||
341 | BUG_ON(key->key == INVALID_KEY); | 369 | BUG_ON(key->key == INVALID_KEY); |
342 | 370 | ||
343 | head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; | 371 | head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; |
344 | list_for_each_entry(event, head, hash_entry) | 372 | list_for_each_entry(event, head, hash_entry) |
345 | if (event->key.key == key->key && event->key.info == key->info) | 373 | if (event->key.key == key->key && event->key.info == key->info) |
346 | return event; | 374 | return event; |
@@ -353,13 +381,14 @@ static struct kvm_event *find_create_kvm_event(struct event_key *key) | |||
353 | return event; | 381 | return event; |
354 | } | 382 | } |
355 | 383 | ||
356 | static bool handle_begin_event(struct vcpu_event_record *vcpu_record, | 384 | static bool handle_begin_event(struct perf_kvm *kvm, |
385 | struct vcpu_event_record *vcpu_record, | ||
357 | struct event_key *key, u64 timestamp) | 386 | struct event_key *key, u64 timestamp) |
358 | { | 387 | { |
359 | struct kvm_event *event = NULL; | 388 | struct kvm_event *event = NULL; |
360 | 389 | ||
361 | if (key->key != INVALID_KEY) | 390 | if (key->key != INVALID_KEY) |
362 | event = find_create_kvm_event(key); | 391 | event = find_create_kvm_event(kvm, key); |
363 | 392 | ||
364 | vcpu_record->last_event = event; | 393 | vcpu_record->last_event = event; |
365 | vcpu_record->start_time = timestamp; | 394 | vcpu_record->start_time = timestamp; |
@@ -396,8 +425,10 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, | |||
396 | return true; | 425 | return true; |
397 | } | 426 | } |
398 | 427 | ||
399 | static bool handle_end_event(struct vcpu_event_record *vcpu_record, | 428 | static bool handle_end_event(struct perf_kvm *kvm, |
400 | struct event_key *key, u64 timestamp) | 429 | struct vcpu_event_record *vcpu_record, |
430 | struct event_key *key, | ||
431 | u64 timestamp) | ||
401 | { | 432 | { |
402 | struct kvm_event *event; | 433 | struct kvm_event *event; |
403 | u64 time_begin, time_diff; | 434 | u64 time_begin, time_diff; |
@@ -419,7 +450,7 @@ static bool handle_end_event(struct vcpu_event_record *vcpu_record, | |||
419 | return true; | 450 | return true; |
420 | 451 | ||
421 | if (!event) | 452 | if (!event) |
422 | event = find_create_kvm_event(key); | 453 | event = find_create_kvm_event(kvm, key); |
423 | 454 | ||
424 | if (!event) | 455 | if (!event) |
425 | return false; | 456 | return false; |
@@ -455,7 +486,9 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, | |||
455 | return thread->priv; | 486 | return thread->priv; |
456 | } | 487 | } |
457 | 488 | ||
458 | static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, | 489 | static bool handle_kvm_event(struct perf_kvm *kvm, |
490 | struct thread *thread, | ||
491 | struct perf_evsel *evsel, | ||
459 | struct perf_sample *sample) | 492 | struct perf_sample *sample) |
460 | { | 493 | { |
461 | struct vcpu_event_record *vcpu_record; | 494 | struct vcpu_event_record *vcpu_record; |
@@ -465,22 +498,15 @@ static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, | |||
465 | if (!vcpu_record) | 498 | if (!vcpu_record) |
466 | return true; | 499 | return true; |
467 | 500 | ||
468 | if (events_ops->is_begin_event(evsel, sample, &key)) | 501 | if (kvm->events_ops->is_begin_event(evsel, sample, &key)) |
469 | return handle_begin_event(vcpu_record, &key, sample->time); | 502 | return handle_begin_event(kvm, vcpu_record, &key, sample->time); |
470 | 503 | ||
471 | if (events_ops->is_end_event(evsel, sample, &key)) | 504 | if (kvm->events_ops->is_end_event(evsel, sample, &key)) |
472 | return handle_end_event(vcpu_record, &key, sample->time); | 505 | return handle_end_event(kvm, vcpu_record, &key, sample->time); |
473 | 506 | ||
474 | return true; | 507 | return true; |
475 | } | 508 | } |
476 | 509 | ||
477 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
478 | struct kvm_event_key { | ||
479 | const char *name; | ||
480 | key_cmp_fun key; | ||
481 | }; | ||
482 | |||
483 | static int trace_vcpu = -1; | ||
484 | #define GET_EVENT_KEY(func, field) \ | 510 | #define GET_EVENT_KEY(func, field) \ |
485 | static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ | 511 | static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ |
486 | { \ | 512 | { \ |
@@ -515,29 +541,25 @@ static struct kvm_event_key keys[] = { | |||
515 | { NULL, NULL } | 541 | { NULL, NULL } |
516 | }; | 542 | }; |
517 | 543 | ||
518 | static const char *sort_key = "sample"; | 544 | static bool select_key(struct perf_kvm *kvm) |
519 | static key_cmp_fun compare; | ||
520 | |||
521 | static bool select_key(void) | ||
522 | { | 545 | { |
523 | int i; | 546 | int i; |
524 | 547 | ||
525 | for (i = 0; keys[i].name; i++) { | 548 | for (i = 0; keys[i].name; i++) { |
526 | if (!strcmp(keys[i].name, sort_key)) { | 549 | if (!strcmp(keys[i].name, kvm->sort_key)) { |
527 | compare = keys[i].key; | 550 | kvm->compare = keys[i].key; |
528 | return true; | 551 | return true; |
529 | } | 552 | } |
530 | } | 553 | } |
531 | 554 | ||
532 | pr_err("Unknown compare key:%s\n", sort_key); | 555 | pr_err("Unknown compare key:%s\n", kvm->sort_key); |
533 | return false; | 556 | return false; |
534 | } | 557 | } |
535 | 558 | ||
536 | static struct rb_root result; | 559 | static void insert_to_result(struct rb_root *result, struct kvm_event *event, |
537 | static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, | 560 | key_cmp_fun bigger, int vcpu) |
538 | int vcpu) | ||
539 | { | 561 | { |
540 | struct rb_node **rb = &result.rb_node; | 562 | struct rb_node **rb = &result->rb_node; |
541 | struct rb_node *parent = NULL; | 563 | struct rb_node *parent = NULL; |
542 | struct kvm_event *p; | 564 | struct kvm_event *p; |
543 | 565 | ||
@@ -552,13 +574,15 @@ static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, | |||
552 | } | 574 | } |
553 | 575 | ||
554 | rb_link_node(&event->rb, parent, rb); | 576 | rb_link_node(&event->rb, parent, rb); |
555 | rb_insert_color(&event->rb, &result); | 577 | rb_insert_color(&event->rb, result); |
556 | } | 578 | } |
557 | 579 | ||
558 | static void update_total_count(struct kvm_event *event, int vcpu) | 580 | static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event) |
559 | { | 581 | { |
560 | total_count += get_event_count(event, vcpu); | 582 | int vcpu = kvm->trace_vcpu; |
561 | total_time += get_event_time(event, vcpu); | 583 | |
584 | kvm->total_count += get_event_count(event, vcpu); | ||
585 | kvm->total_time += get_event_time(event, vcpu); | ||
562 | } | 586 | } |
563 | 587 | ||
564 | static bool event_is_valid(struct kvm_event *event, int vcpu) | 588 | static bool event_is_valid(struct kvm_event *event, int vcpu) |
@@ -566,28 +590,30 @@ static bool event_is_valid(struct kvm_event *event, int vcpu) | |||
566 | return !!get_event_count(event, vcpu); | 590 | return !!get_event_count(event, vcpu); |
567 | } | 591 | } |
568 | 592 | ||
569 | static void sort_result(int vcpu) | 593 | static void sort_result(struct perf_kvm *kvm) |
570 | { | 594 | { |
571 | unsigned int i; | 595 | unsigned int i; |
596 | int vcpu = kvm->trace_vcpu; | ||
572 | struct kvm_event *event; | 597 | struct kvm_event *event; |
573 | 598 | ||
574 | for (i = 0; i < EVENTS_CACHE_SIZE; i++) | 599 | for (i = 0; i < EVENTS_CACHE_SIZE; i++) |
575 | list_for_each_entry(event, &kvm_events_cache[i], hash_entry) | 600 | list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) |
576 | if (event_is_valid(event, vcpu)) { | 601 | if (event_is_valid(event, vcpu)) { |
577 | update_total_count(event, vcpu); | 602 | update_total_count(kvm, event); |
578 | insert_to_result(event, compare, vcpu); | 603 | insert_to_result(&kvm->result, event, |
604 | kvm->compare, vcpu); | ||
579 | } | 605 | } |
580 | } | 606 | } |
581 | 607 | ||
582 | /* returns left most element of result, and erase it */ | 608 | /* returns left most element of result, and erase it */ |
583 | static struct kvm_event *pop_from_result(void) | 609 | static struct kvm_event *pop_from_result(struct rb_root *result) |
584 | { | 610 | { |
585 | struct rb_node *node = rb_first(&result); | 611 | struct rb_node *node = rb_first(result); |
586 | 612 | ||
587 | if (!node) | 613 | if (!node) |
588 | return NULL; | 614 | return NULL; |
589 | 615 | ||
590 | rb_erase(node, &result); | 616 | rb_erase(node, result); |
591 | return container_of(node, struct kvm_event, rb); | 617 | return container_of(node, struct kvm_event, rb); |
592 | } | 618 | } |
593 | 619 | ||
@@ -601,14 +627,15 @@ static void print_vcpu_info(int vcpu) | |||
601 | pr_info("VCPU %d:\n\n", vcpu); | 627 | pr_info("VCPU %d:\n\n", vcpu); |
602 | } | 628 | } |
603 | 629 | ||
604 | static void print_result(int vcpu) | 630 | static void print_result(struct perf_kvm *kvm) |
605 | { | 631 | { |
606 | char decode[20]; | 632 | char decode[20]; |
607 | struct kvm_event *event; | 633 | struct kvm_event *event; |
634 | int vcpu = kvm->trace_vcpu; | ||
608 | 635 | ||
609 | pr_info("\n\n"); | 636 | pr_info("\n\n"); |
610 | print_vcpu_info(vcpu); | 637 | print_vcpu_info(vcpu); |
611 | pr_info("%20s ", events_ops->name); | 638 | pr_info("%20s ", kvm->events_ops->name); |
612 | pr_info("%10s ", "Samples"); | 639 | pr_info("%10s ", "Samples"); |
613 | pr_info("%9s ", "Samples%"); | 640 | pr_info("%9s ", "Samples%"); |
614 | 641 | ||
@@ -616,33 +643,34 @@ static void print_result(int vcpu) | |||
616 | pr_info("%16s ", "Avg time"); | 643 | pr_info("%16s ", "Avg time"); |
617 | pr_info("\n\n"); | 644 | pr_info("\n\n"); |
618 | 645 | ||
619 | while ((event = pop_from_result())) { | 646 | while ((event = pop_from_result(&kvm->result))) { |
620 | u64 ecount, etime; | 647 | u64 ecount, etime; |
621 | 648 | ||
622 | ecount = get_event_count(event, vcpu); | 649 | ecount = get_event_count(event, vcpu); |
623 | etime = get_event_time(event, vcpu); | 650 | etime = get_event_time(event, vcpu); |
624 | 651 | ||
625 | events_ops->decode_key(&event->key, decode); | 652 | kvm->events_ops->decode_key(kvm, &event->key, decode); |
626 | pr_info("%20s ", decode); | 653 | pr_info("%20s ", decode); |
627 | pr_info("%10llu ", (unsigned long long)ecount); | 654 | pr_info("%10llu ", (unsigned long long)ecount); |
628 | pr_info("%8.2f%% ", (double)ecount / total_count * 100); | 655 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); |
629 | pr_info("%8.2f%% ", (double)etime / total_time * 100); | 656 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); |
630 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, | 657 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, |
631 | kvm_event_rel_stddev(vcpu, event)); | 658 | kvm_event_rel_stddev(vcpu, event)); |
632 | pr_info("\n"); | 659 | pr_info("\n"); |
633 | } | 660 | } |
634 | 661 | ||
635 | pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", | 662 | pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", |
636 | (unsigned long long)total_count, total_time / 1e3); | 663 | (unsigned long long)kvm->total_count, kvm->total_time / 1e3); |
637 | } | 664 | } |
638 | 665 | ||
639 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 666 | static int process_sample_event(struct perf_tool *tool, |
640 | union perf_event *event, | 667 | union perf_event *event, |
641 | struct perf_sample *sample, | 668 | struct perf_sample *sample, |
642 | struct perf_evsel *evsel, | 669 | struct perf_evsel *evsel, |
643 | struct machine *machine) | 670 | struct machine *machine) |
644 | { | 671 | { |
645 | struct thread *thread = machine__findnew_thread(machine, sample->tid); | 672 | struct thread *thread = machine__findnew_thread(machine, sample->tid); |
673 | struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool); | ||
646 | 674 | ||
647 | if (thread == NULL) { | 675 | if (thread == NULL) { |
648 | pr_debug("problem processing %d event, skipping it.\n", | 676 | pr_debug("problem processing %d event, skipping it.\n", |
@@ -650,18 +678,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
650 | return -1; | 678 | return -1; |
651 | } | 679 | } |
652 | 680 | ||
653 | if (!handle_kvm_event(thread, evsel, sample)) | 681 | if (!handle_kvm_event(kvm, thread, evsel, sample)) |
654 | return -1; | 682 | return -1; |
655 | 683 | ||
656 | return 0; | 684 | return 0; |
657 | } | 685 | } |
658 | 686 | ||
659 | static struct perf_tool eops = { | ||
660 | .sample = process_sample_event, | ||
661 | .comm = perf_event__process_comm, | ||
662 | .ordered_samples = true, | ||
663 | }; | ||
664 | |||
665 | static int get_cpu_isa(struct perf_session *session) | 687 | static int get_cpu_isa(struct perf_session *session) |
666 | { | 688 | { |
667 | char *cpuid = session->header.env.cpuid; | 689 | char *cpuid = session->header.env.cpuid; |
@@ -679,34 +701,43 @@ static int get_cpu_isa(struct perf_session *session) | |||
679 | return isa; | 701 | return isa; |
680 | } | 702 | } |
681 | 703 | ||
682 | static const char *file_name; | 704 | static int read_events(struct perf_kvm *kvm) |
683 | |||
684 | static int read_events(void) | ||
685 | { | 705 | { |
686 | struct perf_session *kvm_session; | ||
687 | int ret; | 706 | int ret; |
688 | 707 | ||
689 | kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); | 708 | struct perf_tool eops = { |
690 | if (!kvm_session) { | 709 | .sample = process_sample_event, |
710 | .comm = perf_event__process_comm, | ||
711 | .ordered_samples = true, | ||
712 | }; | ||
713 | |||
714 | kvm->tool = eops; | ||
715 | kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false, | ||
716 | &kvm->tool); | ||
717 | if (!kvm->session) { | ||
691 | pr_err("Initializing perf session failed\n"); | 718 | pr_err("Initializing perf session failed\n"); |
692 | return -EINVAL; | 719 | return -EINVAL; |
693 | } | 720 | } |
694 | 721 | ||
695 | if (!perf_session__has_traces(kvm_session, "kvm record")) | 722 | if (!perf_session__has_traces(kvm->session, "kvm record")) |
696 | return -EINVAL; | 723 | return -EINVAL; |
697 | 724 | ||
698 | /* | 725 | /* |
699 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not | 726 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not |
700 | * traced in the old kernel. | 727 | * traced in the old kernel. |
701 | */ | 728 | */ |
702 | ret = get_cpu_isa(kvm_session); | 729 | ret = get_cpu_isa(kvm->session); |
703 | 730 | ||
704 | if (ret < 0) | 731 | if (ret < 0) |
705 | return ret; | 732 | return ret; |
706 | 733 | ||
707 | cpu_isa = ret; | 734 | if (ret == 1) { |
735 | kvm->exit_reasons = vmx_exit_reasons; | ||
736 | kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); | ||
737 | kvm->exit_reasons_isa = "VMX"; | ||
738 | } | ||
708 | 739 | ||
709 | return perf_session__process_events(kvm_session, &eops); | 740 | return perf_session__process_events(kvm->session, &kvm->tool); |
710 | } | 741 | } |
711 | 742 | ||
712 | static bool verify_vcpu(int vcpu) | 743 | static bool verify_vcpu(int vcpu) |
@@ -719,28 +750,30 @@ static bool verify_vcpu(int vcpu) | |||
719 | return true; | 750 | return true; |
720 | } | 751 | } |
721 | 752 | ||
722 | static int kvm_events_report_vcpu(int vcpu) | 753 | static int kvm_events_report_vcpu(struct perf_kvm *kvm) |
723 | { | 754 | { |
724 | int ret = -EINVAL; | 755 | int ret = -EINVAL; |
756 | int vcpu = kvm->trace_vcpu; | ||
725 | 757 | ||
726 | if (!verify_vcpu(vcpu)) | 758 | if (!verify_vcpu(vcpu)) |
727 | goto exit; | 759 | goto exit; |
728 | 760 | ||
729 | if (!select_key()) | 761 | if (!select_key(kvm)) |
730 | goto exit; | 762 | goto exit; |
731 | 763 | ||
732 | if (!register_kvm_events_ops()) | 764 | if (!register_kvm_events_ops(kvm)) |
733 | goto exit; | 765 | goto exit; |
734 | 766 | ||
735 | init_kvm_event_record(); | 767 | init_kvm_event_record(kvm); |
736 | setup_pager(); | 768 | setup_pager(); |
737 | 769 | ||
738 | ret = read_events(); | 770 | ret = read_events(kvm); |
739 | if (ret) | 771 | if (ret) |
740 | goto exit; | 772 | goto exit; |
741 | 773 | ||
742 | sort_result(vcpu); | 774 | sort_result(kvm); |
743 | print_result(vcpu); | 775 | print_result(kvm); |
776 | |||
744 | exit: | 777 | exit: |
745 | return ret; | 778 | return ret; |
746 | } | 779 | } |
@@ -765,7 +798,7 @@ static const char * const record_args[] = { | |||
765 | _p; \ | 798 | _p; \ |
766 | }) | 799 | }) |
767 | 800 | ||
768 | static int kvm_events_record(int argc, const char **argv) | 801 | static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv) |
769 | { | 802 | { |
770 | unsigned int rec_argc, i, j; | 803 | unsigned int rec_argc, i, j; |
771 | const char **rec_argv; | 804 | const char **rec_argv; |
@@ -780,7 +813,7 @@ static int kvm_events_record(int argc, const char **argv) | |||
780 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); | 813 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); |
781 | 814 | ||
782 | rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); | 815 | rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); |
783 | rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); | 816 | rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); |
784 | 817 | ||
785 | for (j = 1; j < (unsigned int)argc; j++, i++) | 818 | for (j = 1; j < (unsigned int)argc; j++, i++) |
786 | rec_argv[i] = argv[j]; | 819 | rec_argv[i] = argv[j]; |
@@ -788,24 +821,24 @@ static int kvm_events_record(int argc, const char **argv) | |||
788 | return cmd_record(i, rec_argv, NULL); | 821 | return cmd_record(i, rec_argv, NULL); |
789 | } | 822 | } |
790 | 823 | ||
791 | static const char * const kvm_events_report_usage[] = { | 824 | static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv) |
792 | "perf kvm stat report [<options>]", | 825 | { |
793 | NULL | 826 | const struct option kvm_events_report_options[] = { |
794 | }; | 827 | OPT_STRING(0, "event", &kvm->report_event, "report event", |
828 | "event for reporting: vmexit, mmio, ioport"), | ||
829 | OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, | ||
830 | "vcpu id to report"), | ||
831 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", | ||
832 | "key for sorting: sample(sort by samples number)" | ||
833 | " time (sort by avg time)"), | ||
834 | OPT_END() | ||
835 | }; | ||
795 | 836 | ||
796 | static const struct option kvm_events_report_options[] = { | 837 | const char * const kvm_events_report_usage[] = { |
797 | OPT_STRING(0, "event", &report_event, "report event", | 838 | "perf kvm stat report [<options>]", |
798 | "event for reporting: vmexit, mmio, ioport"), | 839 | NULL |
799 | OPT_INTEGER(0, "vcpu", &trace_vcpu, | 840 | }; |
800 | "vcpu id to report"), | ||
801 | OPT_STRING('k', "key", &sort_key, "sort-key", | ||
802 | "key for sorting: sample(sort by samples number)" | ||
803 | " time (sort by avg time)"), | ||
804 | OPT_END() | ||
805 | }; | ||
806 | 841 | ||
807 | static int kvm_events_report(int argc, const char **argv) | ||
808 | { | ||
809 | symbol__init(); | 842 | symbol__init(); |
810 | 843 | ||
811 | if (argc) { | 844 | if (argc) { |
@@ -817,7 +850,7 @@ static int kvm_events_report(int argc, const char **argv) | |||
817 | kvm_events_report_options); | 850 | kvm_events_report_options); |
818 | } | 851 | } |
819 | 852 | ||
820 | return kvm_events_report_vcpu(trace_vcpu); | 853 | return kvm_events_report_vcpu(kvm); |
821 | } | 854 | } |
822 | 855 | ||
823 | static void print_kvm_stat_usage(void) | 856 | static void print_kvm_stat_usage(void) |
@@ -831,7 +864,7 @@ static void print_kvm_stat_usage(void) | |||
831 | printf("\nOtherwise, it is the alias of 'perf stat':\n"); | 864 | printf("\nOtherwise, it is the alias of 'perf stat':\n"); |
832 | } | 865 | } |
833 | 866 | ||
834 | static int kvm_cmd_stat(int argc, const char **argv) | 867 | static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv) |
835 | { | 868 | { |
836 | if (argc == 1) { | 869 | if (argc == 1) { |
837 | print_kvm_stat_usage(); | 870 | print_kvm_stat_usage(); |
@@ -839,44 +872,16 @@ static int kvm_cmd_stat(int argc, const char **argv) | |||
839 | } | 872 | } |
840 | 873 | ||
841 | if (!strncmp(argv[1], "rec", 3)) | 874 | if (!strncmp(argv[1], "rec", 3)) |
842 | return kvm_events_record(argc - 1, argv + 1); | 875 | return kvm_events_record(kvm, argc - 1, argv + 1); |
843 | 876 | ||
844 | if (!strncmp(argv[1], "rep", 3)) | 877 | if (!strncmp(argv[1], "rep", 3)) |
845 | return kvm_events_report(argc - 1 , argv + 1); | 878 | return kvm_events_report(kvm, argc - 1 , argv + 1); |
846 | 879 | ||
847 | perf_stat: | 880 | perf_stat: |
848 | return cmd_stat(argc, argv, NULL); | 881 | return cmd_stat(argc, argv, NULL); |
849 | } | 882 | } |
850 | 883 | ||
851 | static char name_buffer[256]; | 884 | static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv) |
852 | |||
853 | static const char * const kvm_usage[] = { | ||
854 | "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", | ||
855 | NULL | ||
856 | }; | ||
857 | |||
858 | static const struct option kvm_options[] = { | ||
859 | OPT_STRING('i', "input", &file_name, "file", | ||
860 | "Input file name"), | ||
861 | OPT_STRING('o', "output", &file_name, "file", | ||
862 | "Output file name"), | ||
863 | OPT_BOOLEAN(0, "guest", &perf_guest, | ||
864 | "Collect guest os data"), | ||
865 | OPT_BOOLEAN(0, "host", &perf_host, | ||
866 | "Collect host os data"), | ||
867 | OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", | ||
868 | "guest mount directory under which every guest os" | ||
869 | " instance has a subdir"), | ||
870 | OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, | ||
871 | "file", "file saving guest os vmlinux"), | ||
872 | OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, | ||
873 | "file", "file saving guest os /proc/kallsyms"), | ||
874 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | ||
875 | "file", "file saving guest os /proc/modules"), | ||
876 | OPT_END() | ||
877 | }; | ||
878 | |||
879 | static int __cmd_record(int argc, const char **argv) | ||
880 | { | 885 | { |
881 | int rec_argc, i = 0, j; | 886 | int rec_argc, i = 0, j; |
882 | const char **rec_argv; | 887 | const char **rec_argv; |
@@ -885,7 +890,7 @@ static int __cmd_record(int argc, const char **argv) | |||
885 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 890 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
886 | rec_argv[i++] = strdup("record"); | 891 | rec_argv[i++] = strdup("record"); |
887 | rec_argv[i++] = strdup("-o"); | 892 | rec_argv[i++] = strdup("-o"); |
888 | rec_argv[i++] = strdup(file_name); | 893 | rec_argv[i++] = strdup(kvm->file_name); |
889 | for (j = 1; j < argc; j++, i++) | 894 | for (j = 1; j < argc; j++, i++) |
890 | rec_argv[i] = argv[j]; | 895 | rec_argv[i] = argv[j]; |
891 | 896 | ||
@@ -894,7 +899,7 @@ static int __cmd_record(int argc, const char **argv) | |||
894 | return cmd_record(i, rec_argv, NULL); | 899 | return cmd_record(i, rec_argv, NULL); |
895 | } | 900 | } |
896 | 901 | ||
897 | static int __cmd_report(int argc, const char **argv) | 902 | static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv) |
898 | { | 903 | { |
899 | int rec_argc, i = 0, j; | 904 | int rec_argc, i = 0, j; |
900 | const char **rec_argv; | 905 | const char **rec_argv; |
@@ -903,7 +908,7 @@ static int __cmd_report(int argc, const char **argv) | |||
903 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 908 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
904 | rec_argv[i++] = strdup("report"); | 909 | rec_argv[i++] = strdup("report"); |
905 | rec_argv[i++] = strdup("-i"); | 910 | rec_argv[i++] = strdup("-i"); |
906 | rec_argv[i++] = strdup(file_name); | 911 | rec_argv[i++] = strdup(kvm->file_name); |
907 | for (j = 1; j < argc; j++, i++) | 912 | for (j = 1; j < argc; j++, i++) |
908 | rec_argv[i] = argv[j]; | 913 | rec_argv[i] = argv[j]; |
909 | 914 | ||
@@ -912,7 +917,7 @@ static int __cmd_report(int argc, const char **argv) | |||
912 | return cmd_report(i, rec_argv, NULL); | 917 | return cmd_report(i, rec_argv, NULL); |
913 | } | 918 | } |
914 | 919 | ||
915 | static int __cmd_buildid_list(int argc, const char **argv) | 920 | static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv) |
916 | { | 921 | { |
917 | int rec_argc, i = 0, j; | 922 | int rec_argc, i = 0, j; |
918 | const char **rec_argv; | 923 | const char **rec_argv; |
@@ -921,7 +926,7 @@ static int __cmd_buildid_list(int argc, const char **argv) | |||
921 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 926 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
922 | rec_argv[i++] = strdup("buildid-list"); | 927 | rec_argv[i++] = strdup("buildid-list"); |
923 | rec_argv[i++] = strdup("-i"); | 928 | rec_argv[i++] = strdup("-i"); |
924 | rec_argv[i++] = strdup(file_name); | 929 | rec_argv[i++] = strdup(kvm->file_name); |
925 | for (j = 1; j < argc; j++, i++) | 930 | for (j = 1; j < argc; j++, i++) |
926 | rec_argv[i] = argv[j]; | 931 | rec_argv[i] = argv[j]; |
927 | 932 | ||
@@ -932,6 +937,43 @@ static int __cmd_buildid_list(int argc, const char **argv) | |||
932 | 937 | ||
933 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | 938 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) |
934 | { | 939 | { |
940 | struct perf_kvm kvm = { | ||
941 | .trace_vcpu = -1, | ||
942 | .report_event = "vmexit", | ||
943 | .sort_key = "sample", | ||
944 | |||
945 | .exit_reasons = svm_exit_reasons, | ||
946 | .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), | ||
947 | .exit_reasons_isa = "SVM", | ||
948 | }; | ||
949 | |||
950 | const struct option kvm_options[] = { | ||
951 | OPT_STRING('i', "input", &kvm.file_name, "file", | ||
952 | "Input file name"), | ||
953 | OPT_STRING('o', "output", &kvm.file_name, "file", | ||
954 | "Output file name"), | ||
955 | OPT_BOOLEAN(0, "guest", &perf_guest, | ||
956 | "Collect guest os data"), | ||
957 | OPT_BOOLEAN(0, "host", &perf_host, | ||
958 | "Collect host os data"), | ||
959 | OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", | ||
960 | "guest mount directory under which every guest os" | ||
961 | " instance has a subdir"), | ||
962 | OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, | ||
963 | "file", "file saving guest os vmlinux"), | ||
964 | OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, | ||
965 | "file", "file saving guest os /proc/kallsyms"), | ||
966 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | ||
967 | "file", "file saving guest os /proc/modules"), | ||
968 | OPT_END() | ||
969 | }; | ||
970 | |||
971 | |||
972 | const char * const kvm_usage[] = { | ||
973 | "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", | ||
974 | NULL | ||
975 | }; | ||
976 | |||
935 | perf_host = 0; | 977 | perf_host = 0; |
936 | perf_guest = 1; | 978 | perf_guest = 1; |
937 | 979 | ||
@@ -943,28 +985,32 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | |||
943 | if (!perf_host) | 985 | if (!perf_host) |
944 | perf_guest = 1; | 986 | perf_guest = 1; |
945 | 987 | ||
946 | if (!file_name) { | 988 | if (!kvm.file_name) { |
947 | if (perf_host && !perf_guest) | 989 | if (perf_host && !perf_guest) |
948 | sprintf(name_buffer, "perf.data.host"); | 990 | kvm.file_name = strdup("perf.data.host"); |
949 | else if (!perf_host && perf_guest) | 991 | else if (!perf_host && perf_guest) |
950 | sprintf(name_buffer, "perf.data.guest"); | 992 | kvm.file_name = strdup("perf.data.guest"); |
951 | else | 993 | else |
952 | sprintf(name_buffer, "perf.data.kvm"); | 994 | kvm.file_name = strdup("perf.data.kvm"); |
953 | file_name = name_buffer; | 995 | |
996 | if (!kvm.file_name) { | ||
997 | pr_err("Failed to allocate memory for filename\n"); | ||
998 | return -ENOMEM; | ||
999 | } | ||
954 | } | 1000 | } |
955 | 1001 | ||
956 | if (!strncmp(argv[0], "rec", 3)) | 1002 | if (!strncmp(argv[0], "rec", 3)) |
957 | return __cmd_record(argc, argv); | 1003 | return __cmd_record(&kvm, argc, argv); |
958 | else if (!strncmp(argv[0], "rep", 3)) | 1004 | else if (!strncmp(argv[0], "rep", 3)) |
959 | return __cmd_report(argc, argv); | 1005 | return __cmd_report(&kvm, argc, argv); |
960 | else if (!strncmp(argv[0], "diff", 4)) | 1006 | else if (!strncmp(argv[0], "diff", 4)) |
961 | return cmd_diff(argc, argv, NULL); | 1007 | return cmd_diff(argc, argv, NULL); |
962 | else if (!strncmp(argv[0], "top", 3)) | 1008 | else if (!strncmp(argv[0], "top", 3)) |
963 | return cmd_top(argc, argv, NULL); | 1009 | return cmd_top(argc, argv, NULL); |
964 | else if (!strncmp(argv[0], "buildid-list", 12)) | 1010 | else if (!strncmp(argv[0], "buildid-list", 12)) |
965 | return __cmd_buildid_list(argc, argv); | 1011 | return __cmd_buildid_list(&kvm, argc, argv); |
966 | else if (!strncmp(argv[0], "stat", 4)) | 1012 | else if (!strncmp(argv[0], "stat", 4)) |
967 | return kvm_cmd_stat(argc, argv); | 1013 | return kvm_cmd_stat(&kvm, argc, argv); |
968 | else | 1014 | else |
969 | usage_with_options(kvm_usage, kvm_options); | 1015 | usage_with_options(kvm_usage, kvm_options); |
970 | 1016 | ||
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 7d6e09949880..6f5f328157aa 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -823,12 +823,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
823 | return 0; | 823 | return 0; |
824 | } | 824 | } |
825 | 825 | ||
826 | static struct perf_tool eops = { | ||
827 | .sample = process_sample_event, | ||
828 | .comm = perf_event__process_comm, | ||
829 | .ordered_samples = true, | ||
830 | }; | ||
831 | |||
832 | static const struct perf_evsel_str_handler lock_tracepoints[] = { | 826 | static const struct perf_evsel_str_handler lock_tracepoints[] = { |
833 | { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ | 827 | { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ |
834 | { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ | 828 | { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ |
@@ -838,6 +832,11 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = { | |||
838 | 832 | ||
839 | static int read_events(void) | 833 | static int read_events(void) |
840 | { | 834 | { |
835 | struct perf_tool eops = { | ||
836 | .sample = process_sample_event, | ||
837 | .comm = perf_event__process_comm, | ||
838 | .ordered_samples = true, | ||
839 | }; | ||
841 | session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); | 840 | session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); |
842 | if (!session) { | 841 | if (!session) { |
843 | pr_err("Initializing perf session failed\n"); | 842 | pr_err("Initializing perf session failed\n"); |
@@ -878,53 +877,11 @@ static int __cmd_report(void) | |||
878 | return 0; | 877 | return 0; |
879 | } | 878 | } |
880 | 879 | ||
881 | static const char * const report_usage[] = { | ||
882 | "perf lock report [<options>]", | ||
883 | NULL | ||
884 | }; | ||
885 | |||
886 | static const struct option report_options[] = { | ||
887 | OPT_STRING('k', "key", &sort_key, "acquired", | ||
888 | "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), | ||
889 | /* TODO: type */ | ||
890 | OPT_END() | ||
891 | }; | ||
892 | |||
893 | static const char * const info_usage[] = { | ||
894 | "perf lock info [<options>]", | ||
895 | NULL | ||
896 | }; | ||
897 | |||
898 | static const struct option info_options[] = { | ||
899 | OPT_BOOLEAN('t', "threads", &info_threads, | ||
900 | "dump thread list in perf.data"), | ||
901 | OPT_BOOLEAN('m', "map", &info_map, | ||
902 | "map of lock instances (address:name table)"), | ||
903 | OPT_END() | ||
904 | }; | ||
905 | |||
906 | static const char * const lock_usage[] = { | ||
907 | "perf lock [<options>] {record|report|script|info}", | ||
908 | NULL | ||
909 | }; | ||
910 | |||
911 | static const struct option lock_options[] = { | ||
912 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
913 | OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), | ||
914 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), | ||
915 | OPT_END() | ||
916 | }; | ||
917 | |||
918 | static const char *record_args[] = { | ||
919 | "record", | ||
920 | "-R", | ||
921 | "-f", | ||
922 | "-m", "1024", | ||
923 | "-c", "1", | ||
924 | }; | ||
925 | |||
926 | static int __cmd_record(int argc, const char **argv) | 880 | static int __cmd_record(int argc, const char **argv) |
927 | { | 881 | { |
882 | const char *record_args[] = { | ||
883 | "record", "-R", "-f", "-m", "1024", "-c", "1", | ||
884 | }; | ||
928 | unsigned int rec_argc, i, j; | 885 | unsigned int rec_argc, i, j; |
929 | const char **rec_argv; | 886 | const char **rec_argv; |
930 | 887 | ||
@@ -963,6 +920,37 @@ static int __cmd_record(int argc, const char **argv) | |||
963 | 920 | ||
964 | int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) | 921 | int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) |
965 | { | 922 | { |
923 | const struct option info_options[] = { | ||
924 | OPT_BOOLEAN('t', "threads", &info_threads, | ||
925 | "dump thread list in perf.data"), | ||
926 | OPT_BOOLEAN('m', "map", &info_map, | ||
927 | "map of lock instances (address:name table)"), | ||
928 | OPT_END() | ||
929 | }; | ||
930 | const struct option lock_options[] = { | ||
931 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
932 | OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), | ||
933 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), | ||
934 | OPT_END() | ||
935 | }; | ||
936 | const struct option report_options[] = { | ||
937 | OPT_STRING('k', "key", &sort_key, "acquired", | ||
938 | "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), | ||
939 | /* TODO: type */ | ||
940 | OPT_END() | ||
941 | }; | ||
942 | const char * const info_usage[] = { | ||
943 | "perf lock info [<options>]", | ||
944 | NULL | ||
945 | }; | ||
946 | const char * const lock_usage[] = { | ||
947 | "perf lock [<options>] {record|report|script|info}", | ||
948 | NULL | ||
949 | }; | ||
950 | const char * const report_usage[] = { | ||
951 | "perf lock report [<options>]", | ||
952 | NULL | ||
953 | }; | ||
966 | unsigned int i; | 954 | unsigned int i; |
967 | int rc = 0; | 955 | int rc = 0; |
968 | 956 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 118aa8946573..de38a034b129 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -250,19 +250,20 @@ static int opt_set_filter(const struct option *opt __maybe_unused, | |||
250 | return 0; | 250 | return 0; |
251 | } | 251 | } |
252 | 252 | ||
253 | static const char * const probe_usage[] = { | 253 | int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) |
254 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 254 | { |
255 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 255 | const char * const probe_usage[] = { |
256 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 256 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
257 | "perf probe --list", | 257 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
258 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | ||
259 | "perf probe --list", | ||
258 | #ifdef DWARF_SUPPORT | 260 | #ifdef DWARF_SUPPORT |
259 | "perf probe [<options>] --line 'LINEDESC'", | 261 | "perf probe [<options>] --line 'LINEDESC'", |
260 | "perf probe [<options>] --vars 'PROBEPOINT'", | 262 | "perf probe [<options>] --vars 'PROBEPOINT'", |
261 | #endif | 263 | #endif |
262 | NULL | 264 | NULL |
263 | }; | 265 | }; |
264 | 266 | const struct option options[] = { | |
265 | static const struct option options[] = { | ||
266 | OPT_INCR('v', "verbose", &verbose, | 267 | OPT_INCR('v', "verbose", &verbose, |
267 | "be more verbose (show parsed arguments, etc)"), | 268 | "be more verbose (show parsed arguments, etc)"), |
268 | OPT_BOOLEAN('l', "list", ¶ms.list_events, | 269 | OPT_BOOLEAN('l', "list", ¶ms.list_events, |
@@ -325,10 +326,7 @@ static const struct option options[] = { | |||
325 | OPT_CALLBACK('x', "exec", NULL, "executable|path", | 326 | OPT_CALLBACK('x', "exec", NULL, "executable|path", |
326 | "target executable name or path", opt_set_target), | 327 | "target executable name or path", opt_set_target), |
327 | OPT_END() | 328 | OPT_END() |
328 | }; | 329 | }; |
329 | |||
330 | int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | ||
331 | { | ||
332 | int ret; | 330 | int ret; |
333 | 331 | ||
334 | argc = parse_options(argc, argv, options, probe_usage, | 332 | argc = parse_options(argc, argv, options, probe_usage, |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f14cb5fdb91f..e9231659754d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -31,15 +31,6 @@ | |||
31 | #include <sched.h> | 31 | #include <sched.h> |
32 | #include <sys/mman.h> | 32 | #include <sys/mman.h> |
33 | 33 | ||
34 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | ||
35 | |||
36 | #ifdef NO_LIBUNWIND_SUPPORT | ||
37 | static char callchain_help[] = CALLCHAIN_HELP "[fp]"; | ||
38 | #else | ||
39 | static unsigned long default_stack_dump_size = 8192; | ||
40 | static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | ||
41 | #endif | ||
42 | |||
43 | enum write_mode_t { | 34 | enum write_mode_t { |
44 | WRITE_FORCE, | 35 | WRITE_FORCE, |
45 | WRITE_APPEND | 36 | WRITE_APPEND |
@@ -800,7 +791,7 @@ error: | |||
800 | return ret; | 791 | return ret; |
801 | } | 792 | } |
802 | 793 | ||
803 | #ifndef NO_LIBUNWIND_SUPPORT | 794 | #ifdef LIBUNWIND_SUPPORT |
804 | static int get_stack_size(char *str, unsigned long *_size) | 795 | static int get_stack_size(char *str, unsigned long *_size) |
805 | { | 796 | { |
806 | char *endptr; | 797 | char *endptr; |
@@ -826,7 +817,7 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
826 | max_size, str); | 817 | max_size, str); |
827 | return -1; | 818 | return -1; |
828 | } | 819 | } |
829 | #endif /* !NO_LIBUNWIND_SUPPORT */ | 820 | #endif /* LIBUNWIND_SUPPORT */ |
830 | 821 | ||
831 | static int | 822 | static int |
832 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | 823 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, |
@@ -865,9 +856,11 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
865 | "needed for -g fp\n"); | 856 | "needed for -g fp\n"); |
866 | break; | 857 | break; |
867 | 858 | ||
868 | #ifndef NO_LIBUNWIND_SUPPORT | 859 | #ifdef LIBUNWIND_SUPPORT |
869 | /* Dwarf style */ | 860 | /* Dwarf style */ |
870 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | 861 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { |
862 | const unsigned long default_stack_dump_size = 8192; | ||
863 | |||
871 | ret = 0; | 864 | ret = 0; |
872 | rec->opts.call_graph = CALLCHAIN_DWARF; | 865 | rec->opts.call_graph = CALLCHAIN_DWARF; |
873 | rec->opts.stack_dump_size = default_stack_dump_size; | 866 | rec->opts.stack_dump_size = default_stack_dump_size; |
@@ -883,7 +876,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
883 | if (!ret) | 876 | if (!ret) |
884 | pr_debug("callchain: stack dump size %d\n", | 877 | pr_debug("callchain: stack dump size %d\n", |
885 | rec->opts.stack_dump_size); | 878 | rec->opts.stack_dump_size); |
886 | #endif /* !NO_LIBUNWIND_SUPPORT */ | 879 | #endif /* LIBUNWIND_SUPPORT */ |
887 | } else { | 880 | } else { |
888 | pr_err("callchain: Unknown -g option " | 881 | pr_err("callchain: Unknown -g option " |
889 | "value: %s\n", arg); | 882 | "value: %s\n", arg); |
@@ -930,6 +923,14 @@ static struct perf_record record = { | |||
930 | .file_new = true, | 923 | .file_new = true, |
931 | }; | 924 | }; |
932 | 925 | ||
926 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | ||
927 | |||
928 | #ifdef LIBUNWIND_SUPPORT | ||
929 | static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | ||
930 | #else | ||
931 | static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; | ||
932 | #endif | ||
933 | |||
933 | /* | 934 | /* |
934 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing | 935 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing |
935 | * with it and switch to use the library functions in perf_evlist that came | 936 | * with it and switch to use the library functions in perf_evlist that came |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1da243dfbc3e..a61725d89d3e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
320 | const char *evname = perf_evsel__name(pos); | 320 | const char *evname = perf_evsel__name(pos); |
321 | 321 | ||
322 | hists__fprintf_nr_sample_events(hists, evname, stdout); | 322 | hists__fprintf_nr_sample_events(hists, evname, stdout); |
323 | hists__fprintf(hists, NULL, false, true, 0, 0, stdout); | 323 | hists__fprintf(hists, true, 0, 0, stdout); |
324 | fprintf(stdout, "\n\n"); | 324 | fprintf(stdout, "\n\n"); |
325 | } | 325 | } |
326 | 326 | ||
@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
691 | setup_browser(true); | 691 | setup_browser(true); |
692 | else { | 692 | else { |
693 | use_browser = 0; | 693 | use_browser = 0; |
694 | perf_hpp__init(false, false); | 694 | perf_hpp__init(); |
695 | } | 695 | } |
696 | 696 | ||
697 | setup_sorting(report_usage, options); | 697 | setup_sorting(report_usage, options); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 9b9e32eaa805..3488ead3b60c 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1426,7 +1426,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ | |||
1426 | struct perf_evsel *evsel, | 1426 | struct perf_evsel *evsel, |
1427 | struct machine *machine) | 1427 | struct machine *machine) |
1428 | { | 1428 | { |
1429 | struct thread *thread = machine__findnew_thread(machine, sample->pid); | 1429 | struct thread *thread = machine__findnew_thread(machine, sample->tid); |
1430 | int err = 0; | 1430 | int err = 0; |
1431 | 1431 | ||
1432 | if (thread == NULL) { | 1432 | if (thread == NULL) { |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 1be843aa1546..fb9625083a2e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -24,7 +24,6 @@ static u64 last_timestamp; | |||
24 | static u64 nr_unordered; | 24 | static u64 nr_unordered; |
25 | extern const struct option record_options[]; | 25 | extern const struct option record_options[]; |
26 | static bool no_callchain; | 26 | static bool no_callchain; |
27 | static bool show_full_info; | ||
28 | static bool system_wide; | 27 | static bool system_wide; |
29 | static const char *cpu_list; | 28 | static const char *cpu_list; |
30 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
@@ -473,8 +472,6 @@ static int cleanup_scripting(void) | |||
473 | return scripting_ops->stop_script(); | 472 | return scripting_ops->stop_script(); |
474 | } | 473 | } |
475 | 474 | ||
476 | static const char *input_name; | ||
477 | |||
478 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 475 | static int process_sample_event(struct perf_tool *tool __maybe_unused, |
479 | union perf_event *event, | 476 | union perf_event *event, |
480 | struct perf_sample *sample, | 477 | struct perf_sample *sample, |
@@ -1156,20 +1153,40 @@ out: | |||
1156 | return n_args; | 1153 | return n_args; |
1157 | } | 1154 | } |
1158 | 1155 | ||
1159 | static const char * const script_usage[] = { | 1156 | static int have_cmd(int argc, const char **argv) |
1160 | "perf script [<options>]", | 1157 | { |
1161 | "perf script [<options>] record <script> [<record-options>] <command>", | 1158 | char **__argv = malloc(sizeof(const char *) * argc); |
1162 | "perf script [<options>] report <script> [script-args]", | 1159 | |
1163 | "perf script [<options>] <script> [<record-options>] <command>", | 1160 | if (!__argv) { |
1164 | "perf script [<options>] <top-script> [script-args]", | 1161 | pr_err("malloc failed\n"); |
1165 | NULL | 1162 | return -1; |
1166 | }; | 1163 | } |
1164 | |||
1165 | memcpy(__argv, argv, sizeof(const char *) * argc); | ||
1166 | argc = parse_options(argc, (const char **)__argv, record_options, | ||
1167 | NULL, PARSE_OPT_STOP_AT_NON_OPTION); | ||
1168 | free(__argv); | ||
1167 | 1169 | ||
1168 | static const struct option options[] = { | 1170 | system_wide = (argc == 0); |
1171 | |||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | ||
1176 | { | ||
1177 | bool show_full_info = false; | ||
1178 | const char *input_name = NULL; | ||
1179 | char *rec_script_path = NULL; | ||
1180 | char *rep_script_path = NULL; | ||
1181 | struct perf_session *session; | ||
1182 | char *script_path = NULL; | ||
1183 | const char **__argv; | ||
1184 | int i, j, err; | ||
1185 | const struct option options[] = { | ||
1169 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1186 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1170 | "dump raw trace in ASCII"), | 1187 | "dump raw trace in ASCII"), |
1171 | OPT_INCR('v', "verbose", &verbose, | 1188 | OPT_INCR('v', "verbose", &verbose, |
1172 | "be more verbose (show symbol address, etc)"), | 1189 | "be more verbose (show symbol address, etc)"), |
1173 | OPT_BOOLEAN('L', "Latency", &latency_format, | 1190 | OPT_BOOLEAN('L', "Latency", &latency_format, |
1174 | "show latency attributes (irqs/preemption disabled, etc)"), | 1191 | "show latency attributes (irqs/preemption disabled, etc)"), |
1175 | OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", | 1192 | OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", |
@@ -1179,8 +1196,7 @@ static const struct option options[] = { | |||
1179 | parse_scriptname), | 1196 | parse_scriptname), |
1180 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", | 1197 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", |
1181 | "generate perf-script.xx script in specified language"), | 1198 | "generate perf-script.xx script in specified language"), |
1182 | OPT_STRING('i', "input", &input_name, "file", | 1199 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1183 | "input file name"), | ||
1184 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 1200 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
1185 | "do various checks like samples ordering and lost events"), | 1201 | "do various checks like samples ordering and lost events"), |
1186 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1202 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
@@ -1195,10 +1211,9 @@ static const struct option options[] = { | |||
1195 | "comma separated output fields prepend with 'type:'. " | 1211 | "comma separated output fields prepend with 'type:'. " |
1196 | "Valid types: hw,sw,trace,raw. " | 1212 | "Valid types: hw,sw,trace,raw. " |
1197 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 1213 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
1198 | "addr,symoff", | 1214 | "addr,symoff", parse_output_fields), |
1199 | parse_output_fields), | ||
1200 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1215 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1201 | "system-wide collection from all CPUs"), | 1216 | "system-wide collection from all CPUs"), |
1202 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1217 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
1203 | "only consider these symbols"), | 1218 | "only consider these symbols"), |
1204 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 1219 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
@@ -1208,37 +1223,16 @@ static const struct option options[] = { | |||
1208 | "display extended information from perf.data file"), | 1223 | "display extended information from perf.data file"), |
1209 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 1224 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
1210 | "Show the path of [kernel.kallsyms]"), | 1225 | "Show the path of [kernel.kallsyms]"), |
1211 | |||
1212 | OPT_END() | 1226 | OPT_END() |
1213 | }; | 1227 | }; |
1214 | 1228 | const char * const script_usage[] = { | |
1215 | static int have_cmd(int argc, const char **argv) | 1229 | "perf script [<options>]", |
1216 | { | 1230 | "perf script [<options>] record <script> [<record-options>] <command>", |
1217 | char **__argv = malloc(sizeof(const char *) * argc); | 1231 | "perf script [<options>] report <script> [script-args]", |
1218 | 1232 | "perf script [<options>] <script> [<record-options>] <command>", | |
1219 | if (!__argv) { | 1233 | "perf script [<options>] <top-script> [script-args]", |
1220 | pr_err("malloc failed\n"); | 1234 | NULL |
1221 | return -1; | 1235 | }; |
1222 | } | ||
1223 | |||
1224 | memcpy(__argv, argv, sizeof(const char *) * argc); | ||
1225 | argc = parse_options(argc, (const char **)__argv, record_options, | ||
1226 | NULL, PARSE_OPT_STOP_AT_NON_OPTION); | ||
1227 | free(__argv); | ||
1228 | |||
1229 | system_wide = (argc == 0); | ||
1230 | |||
1231 | return 0; | ||
1232 | } | ||
1233 | |||
1234 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | ||
1235 | { | ||
1236 | char *rec_script_path = NULL; | ||
1237 | char *rep_script_path = NULL; | ||
1238 | struct perf_session *session; | ||
1239 | char *script_path = NULL; | ||
1240 | const char **__argv; | ||
1241 | int i, j, err; | ||
1242 | 1236 | ||
1243 | setup_scripting(); | 1237 | setup_scripting(); |
1244 | 1238 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8cd4d81b06e..93b9011fa3e2 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -64,122 +64,12 @@ | |||
64 | #define CNTR_NOT_SUPPORTED "<not supported>" | 64 | #define CNTR_NOT_SUPPORTED "<not supported>" |
65 | #define CNTR_NOT_COUNTED "<not counted>" | 65 | #define CNTR_NOT_COUNTED "<not counted>" |
66 | 66 | ||
67 | static struct perf_event_attr default_attrs[] = { | ||
68 | |||
69 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | ||
70 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, | ||
71 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, | ||
72 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, | ||
73 | |||
74 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, | ||
75 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, | ||
76 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, | ||
77 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, | ||
78 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, | ||
79 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, | ||
80 | |||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * Detailed stats (-d), covering the L1 and last level data caches: | ||
85 | */ | ||
86 | static struct perf_event_attr detailed_attrs[] = { | ||
87 | |||
88 | { .type = PERF_TYPE_HW_CACHE, | ||
89 | .config = | ||
90 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
91 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
92 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
93 | |||
94 | { .type = PERF_TYPE_HW_CACHE, | ||
95 | .config = | ||
96 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
97 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
98 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
99 | |||
100 | { .type = PERF_TYPE_HW_CACHE, | ||
101 | .config = | ||
102 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
103 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
104 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
105 | |||
106 | { .type = PERF_TYPE_HW_CACHE, | ||
107 | .config = | ||
108 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
109 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
110 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
111 | }; | ||
112 | |||
113 | /* | ||
114 | * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: | ||
115 | */ | ||
116 | static struct perf_event_attr very_detailed_attrs[] = { | ||
117 | |||
118 | { .type = PERF_TYPE_HW_CACHE, | ||
119 | .config = | ||
120 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
121 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
122 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
123 | |||
124 | { .type = PERF_TYPE_HW_CACHE, | ||
125 | .config = | ||
126 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
127 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
128 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
129 | |||
130 | { .type = PERF_TYPE_HW_CACHE, | ||
131 | .config = | ||
132 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
133 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
134 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
135 | |||
136 | { .type = PERF_TYPE_HW_CACHE, | ||
137 | .config = | ||
138 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
139 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
140 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
141 | |||
142 | { .type = PERF_TYPE_HW_CACHE, | ||
143 | .config = | ||
144 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
145 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
146 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
147 | |||
148 | { .type = PERF_TYPE_HW_CACHE, | ||
149 | .config = | ||
150 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
151 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
152 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
153 | |||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Very, very detailed stats (-d -d -d), adding prefetch events: | ||
158 | */ | ||
159 | static struct perf_event_attr very_very_detailed_attrs[] = { | ||
160 | |||
161 | { .type = PERF_TYPE_HW_CACHE, | ||
162 | .config = | ||
163 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
164 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
165 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
166 | |||
167 | { .type = PERF_TYPE_HW_CACHE, | ||
168 | .config = | ||
169 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
170 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
171 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
172 | }; | ||
173 | |||
174 | |||
175 | |||
176 | static struct perf_evlist *evsel_list; | 67 | static struct perf_evlist *evsel_list; |
177 | 68 | ||
178 | static struct perf_target target = { | 69 | static struct perf_target target = { |
179 | .uid = UINT_MAX, | 70 | .uid = UINT_MAX, |
180 | }; | 71 | }; |
181 | 72 | ||
182 | static int run_idx = 0; | ||
183 | static int run_count = 1; | 73 | static int run_count = 1; |
184 | static bool no_inherit = false; | 74 | static bool no_inherit = false; |
185 | static bool scale = true; | 75 | static bool scale = true; |
@@ -187,15 +77,12 @@ static bool no_aggr = false; | |||
187 | static pid_t child_pid = -1; | 77 | static pid_t child_pid = -1; |
188 | static bool null_run = false; | 78 | static bool null_run = false; |
189 | static int detailed_run = 0; | 79 | static int detailed_run = 0; |
190 | static bool sync_run = false; | ||
191 | static bool big_num = true; | 80 | static bool big_num = true; |
192 | static int big_num_opt = -1; | 81 | static int big_num_opt = -1; |
193 | static const char *csv_sep = NULL; | 82 | static const char *csv_sep = NULL; |
194 | static bool csv_output = false; | 83 | static bool csv_output = false; |
195 | static bool group = false; | 84 | static bool group = false; |
196 | static const char *output_name = NULL; | ||
197 | static FILE *output = NULL; | 85 | static FILE *output = NULL; |
198 | static int output_fd; | ||
199 | 86 | ||
200 | static volatile int done = 0; | 87 | static volatile int done = 0; |
201 | 88 | ||
@@ -1028,11 +915,6 @@ static void sig_atexit(void) | |||
1028 | kill(getpid(), signr); | 915 | kill(getpid(), signr); |
1029 | } | 916 | } |
1030 | 917 | ||
1031 | static const char * const stat_usage[] = { | ||
1032 | "perf stat [<options>] [<command>]", | ||
1033 | NULL | ||
1034 | }; | ||
1035 | |||
1036 | static int stat__set_big_num(const struct option *opt __maybe_unused, | 918 | static int stat__set_big_num(const struct option *opt __maybe_unused, |
1037 | const char *s __maybe_unused, int unset) | 919 | const char *s __maybe_unused, int unset) |
1038 | { | 920 | { |
@@ -1040,62 +922,119 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, | |||
1040 | return 0; | 922 | return 0; |
1041 | } | 923 | } |
1042 | 924 | ||
1043 | static bool append_file; | ||
1044 | |||
1045 | static const struct option options[] = { | ||
1046 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
1047 | "event selector. use 'perf list' to list available events", | ||
1048 | parse_events_option), | ||
1049 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
1050 | "event filter", parse_filter), | ||
1051 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
1052 | "child tasks do not inherit counters"), | ||
1053 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
1054 | "stat events on existing process id"), | ||
1055 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
1056 | "stat events on existing thread id"), | ||
1057 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
1058 | "system-wide collection from all CPUs"), | ||
1059 | OPT_BOOLEAN('g', "group", &group, | ||
1060 | "put the counters into a counter group"), | ||
1061 | OPT_BOOLEAN('c', "scale", &scale, | ||
1062 | "scale/normalize counters"), | ||
1063 | OPT_INCR('v', "verbose", &verbose, | ||
1064 | "be more verbose (show counter open errors, etc)"), | ||
1065 | OPT_INTEGER('r', "repeat", &run_count, | ||
1066 | "repeat command and print average + stddev (max: 100)"), | ||
1067 | OPT_BOOLEAN('n', "null", &null_run, | ||
1068 | "null run - dont start any counters"), | ||
1069 | OPT_INCR('d', "detailed", &detailed_run, | ||
1070 | "detailed run - start a lot of events"), | ||
1071 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
1072 | "call sync() before starting a run"), | ||
1073 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
1074 | "print large numbers with thousands\' separators", | ||
1075 | stat__set_big_num), | ||
1076 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
1077 | "list of cpus to monitor in system-wide"), | ||
1078 | OPT_BOOLEAN('A', "no-aggr", &no_aggr, | ||
1079 | "disable CPU count aggregation"), | ||
1080 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
1081 | "print counts with custom separator"), | ||
1082 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
1083 | "monitor event in cgroup name only", | ||
1084 | parse_cgroups), | ||
1085 | OPT_STRING('o', "output", &output_name, "file", | ||
1086 | "output file name"), | ||
1087 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
1088 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
1089 | "log output to fd, instead of stderr"), | ||
1090 | OPT_END() | ||
1091 | }; | ||
1092 | |||
1093 | /* | 925 | /* |
1094 | * Add default attributes, if there were no attributes specified or | 926 | * Add default attributes, if there were no attributes specified or |
1095 | * if -d/--detailed, -d -d or -d -d -d is used: | 927 | * if -d/--detailed, -d -d or -d -d -d is used: |
1096 | */ | 928 | */ |
1097 | static int add_default_attributes(void) | 929 | static int add_default_attributes(void) |
1098 | { | 930 | { |
931 | struct perf_event_attr default_attrs[] = { | ||
932 | |||
933 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | ||
934 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, | ||
935 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, | ||
936 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, | ||
937 | |||
938 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, | ||
939 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, | ||
940 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, | ||
941 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, | ||
942 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, | ||
943 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, | ||
944 | |||
945 | }; | ||
946 | |||
947 | /* | ||
948 | * Detailed stats (-d), covering the L1 and last level data caches: | ||
949 | */ | ||
950 | struct perf_event_attr detailed_attrs[] = { | ||
951 | |||
952 | { .type = PERF_TYPE_HW_CACHE, | ||
953 | .config = | ||
954 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
955 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
956 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
957 | |||
958 | { .type = PERF_TYPE_HW_CACHE, | ||
959 | .config = | ||
960 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
961 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
962 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
963 | |||
964 | { .type = PERF_TYPE_HW_CACHE, | ||
965 | .config = | ||
966 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
967 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
968 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
969 | |||
970 | { .type = PERF_TYPE_HW_CACHE, | ||
971 | .config = | ||
972 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
973 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
974 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
975 | }; | ||
976 | |||
977 | /* | ||
978 | * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: | ||
979 | */ | ||
980 | struct perf_event_attr very_detailed_attrs[] = { | ||
981 | |||
982 | { .type = PERF_TYPE_HW_CACHE, | ||
983 | .config = | ||
984 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
985 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
986 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
987 | |||
988 | { .type = PERF_TYPE_HW_CACHE, | ||
989 | .config = | ||
990 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
991 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
992 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
993 | |||
994 | { .type = PERF_TYPE_HW_CACHE, | ||
995 | .config = | ||
996 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
997 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
998 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
999 | |||
1000 | { .type = PERF_TYPE_HW_CACHE, | ||
1001 | .config = | ||
1002 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
1003 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
1004 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
1005 | |||
1006 | { .type = PERF_TYPE_HW_CACHE, | ||
1007 | .config = | ||
1008 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
1009 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
1010 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
1011 | |||
1012 | { .type = PERF_TYPE_HW_CACHE, | ||
1013 | .config = | ||
1014 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
1015 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
1016 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
1017 | |||
1018 | }; | ||
1019 | |||
1020 | /* | ||
1021 | * Very, very detailed stats (-d -d -d), adding prefetch events: | ||
1022 | */ | ||
1023 | struct perf_event_attr very_very_detailed_attrs[] = { | ||
1024 | |||
1025 | { .type = PERF_TYPE_HW_CACHE, | ||
1026 | .config = | ||
1027 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
1028 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
1029 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
1030 | |||
1031 | { .type = PERF_TYPE_HW_CACHE, | ||
1032 | .config = | ||
1033 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
1034 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
1035 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
1036 | }; | ||
1037 | |||
1099 | /* Set attrs if no event is selected and !null_run: */ | 1038 | /* Set attrs if no event is selected and !null_run: */ |
1100 | if (null_run) | 1039 | if (null_run) |
1101 | return 0; | 1040 | return 0; |
@@ -1130,8 +1069,59 @@ static int add_default_attributes(void) | |||
1130 | 1069 | ||
1131 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | 1070 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) |
1132 | { | 1071 | { |
1072 | bool append_file = false, | ||
1073 | sync_run = false; | ||
1074 | int output_fd = 0; | ||
1075 | const char *output_name = NULL; | ||
1076 | const struct option options[] = { | ||
1077 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
1078 | "event selector. use 'perf list' to list available events", | ||
1079 | parse_events_option), | ||
1080 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
1081 | "event filter", parse_filter), | ||
1082 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
1083 | "child tasks do not inherit counters"), | ||
1084 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
1085 | "stat events on existing process id"), | ||
1086 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
1087 | "stat events on existing thread id"), | ||
1088 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
1089 | "system-wide collection from all CPUs"), | ||
1090 | OPT_BOOLEAN('g', "group", &group, | ||
1091 | "put the counters into a counter group"), | ||
1092 | OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"), | ||
1093 | OPT_INCR('v', "verbose", &verbose, | ||
1094 | "be more verbose (show counter open errors, etc)"), | ||
1095 | OPT_INTEGER('r', "repeat", &run_count, | ||
1096 | "repeat command and print average + stddev (max: 100)"), | ||
1097 | OPT_BOOLEAN('n', "null", &null_run, | ||
1098 | "null run - dont start any counters"), | ||
1099 | OPT_INCR('d', "detailed", &detailed_run, | ||
1100 | "detailed run - start a lot of events"), | ||
1101 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
1102 | "call sync() before starting a run"), | ||
1103 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
1104 | "print large numbers with thousands\' separators", | ||
1105 | stat__set_big_num), | ||
1106 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
1107 | "list of cpus to monitor in system-wide"), | ||
1108 | OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), | ||
1109 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
1110 | "print counts with custom separator"), | ||
1111 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
1112 | "monitor event in cgroup name only", parse_cgroups), | ||
1113 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | ||
1114 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
1115 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
1116 | "log output to fd, instead of stderr"), | ||
1117 | OPT_END() | ||
1118 | }; | ||
1119 | const char * const stat_usage[] = { | ||
1120 | "perf stat [<options>] [<command>]", | ||
1121 | NULL | ||
1122 | }; | ||
1133 | struct perf_evsel *pos; | 1123 | struct perf_evsel *pos; |
1134 | int status = -ENOMEM; | 1124 | int status = -ENOMEM, run_idx; |
1135 | const char *mode; | 1125 | const char *mode; |
1136 | 1126 | ||
1137 | setlocale(LC_ALL, ""); | 1127 | setlocale(LC_ALL, ""); |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index b1a8a3b841cc..f251b613b2f3 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -38,9 +38,6 @@ | |||
38 | #define PWR_EVENT_EXIT -1 | 38 | #define PWR_EVENT_EXIT -1 |
39 | 39 | ||
40 | 40 | ||
41 | static const char *input_name; | ||
42 | static const char *output_name = "output.svg"; | ||
43 | |||
44 | static unsigned int numcpus; | 41 | static unsigned int numcpus; |
45 | static u64 min_freq; /* Lowest CPU frequency seen */ | 42 | static u64 min_freq; /* Lowest CPU frequency seen */ |
46 | static u64 max_freq; /* Highest CPU frequency seen */ | 43 | static u64 max_freq; /* Highest CPU frequency seen */ |
@@ -968,16 +965,15 @@ static void write_svg_file(const char *filename) | |||
968 | svg_close(); | 965 | svg_close(); |
969 | } | 966 | } |
970 | 967 | ||
971 | static struct perf_tool perf_timechart = { | 968 | static int __cmd_timechart(const char *input_name, const char *output_name) |
972 | .comm = process_comm_event, | ||
973 | .fork = process_fork_event, | ||
974 | .exit = process_exit_event, | ||
975 | .sample = process_sample_event, | ||
976 | .ordered_samples = true, | ||
977 | }; | ||
978 | |||
979 | static int __cmd_timechart(void) | ||
980 | { | 969 | { |
970 | struct perf_tool perf_timechart = { | ||
971 | .comm = process_comm_event, | ||
972 | .fork = process_fork_event, | ||
973 | .exit = process_exit_event, | ||
974 | .sample = process_sample_event, | ||
975 | .ordered_samples = true, | ||
976 | }; | ||
981 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 977 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
982 | 0, false, &perf_timechart); | 978 | 0, false, &perf_timechart); |
983 | int ret = -EINVAL; | 979 | int ret = -EINVAL; |
@@ -1005,40 +1001,25 @@ out_delete: | |||
1005 | return ret; | 1001 | return ret; |
1006 | } | 1002 | } |
1007 | 1003 | ||
1008 | static const char * const timechart_usage[] = { | ||
1009 | "perf timechart [<options>] {record}", | ||
1010 | NULL | ||
1011 | }; | ||
1012 | |||
1013 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
1014 | static const char * const record_old_args[] = { | ||
1015 | "record", | ||
1016 | "-a", | ||
1017 | "-R", | ||
1018 | "-f", | ||
1019 | "-c", "1", | ||
1020 | "-e", "power:power_start", | ||
1021 | "-e", "power:power_end", | ||
1022 | "-e", "power:power_frequency", | ||
1023 | "-e", "sched:sched_wakeup", | ||
1024 | "-e", "sched:sched_switch", | ||
1025 | }; | ||
1026 | #endif | ||
1027 | |||
1028 | static const char * const record_new_args[] = { | ||
1029 | "record", | ||
1030 | "-a", | ||
1031 | "-R", | ||
1032 | "-f", | ||
1033 | "-c", "1", | ||
1034 | "-e", "power:cpu_frequency", | ||
1035 | "-e", "power:cpu_idle", | ||
1036 | "-e", "sched:sched_wakeup", | ||
1037 | "-e", "sched:sched_switch", | ||
1038 | }; | ||
1039 | |||
1040 | static int __cmd_record(int argc, const char **argv) | 1004 | static int __cmd_record(int argc, const char **argv) |
1041 | { | 1005 | { |
1006 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
1007 | const char * const record_old_args[] = { | ||
1008 | "record", "-a", "-R", "-f", "-c", "1", | ||
1009 | "-e", "power:power_start", | ||
1010 | "-e", "power:power_end", | ||
1011 | "-e", "power:power_frequency", | ||
1012 | "-e", "sched:sched_wakeup", | ||
1013 | "-e", "sched:sched_switch", | ||
1014 | }; | ||
1015 | #endif | ||
1016 | const char * const record_new_args[] = { | ||
1017 | "record", "-a", "-R", "-f", "-c", "1", | ||
1018 | "-e", "power:cpu_frequency", | ||
1019 | "-e", "power:cpu_idle", | ||
1020 | "-e", "sched:sched_wakeup", | ||
1021 | "-e", "sched:sched_switch", | ||
1022 | }; | ||
1042 | unsigned int rec_argc, i, j; | 1023 | unsigned int rec_argc, i, j; |
1043 | const char **rec_argv; | 1024 | const char **rec_argv; |
1044 | const char * const *record_args = record_new_args; | 1025 | const char * const *record_args = record_new_args; |
@@ -1077,27 +1058,28 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
1077 | return 0; | 1058 | return 0; |
1078 | } | 1059 | } |
1079 | 1060 | ||
1080 | static const struct option options[] = { | 1061 | int cmd_timechart(int argc, const char **argv, |
1081 | OPT_STRING('i', "input", &input_name, "file", | 1062 | const char *prefix __maybe_unused) |
1082 | "input file name"), | 1063 | { |
1083 | OPT_STRING('o', "output", &output_name, "file", | 1064 | const char *input_name; |
1084 | "output file name"), | 1065 | const char *output_name = "output.svg"; |
1085 | OPT_INTEGER('w', "width", &svg_page_width, | 1066 | const struct option options[] = { |
1086 | "page width"), | 1067 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1087 | OPT_BOOLEAN('P', "power-only", &power_only, | 1068 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
1088 | "output power data only"), | 1069 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
1070 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | ||
1089 | OPT_CALLBACK('p', "process", NULL, "process", | 1071 | OPT_CALLBACK('p', "process", NULL, "process", |
1090 | "process selector. Pass a pid or process name.", | 1072 | "process selector. Pass a pid or process name.", |
1091 | parse_process), | 1073 | parse_process), |
1092 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1074 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
1093 | "Look for files with symbols relative to this directory"), | 1075 | "Look for files with symbols relative to this directory"), |
1094 | OPT_END() | 1076 | OPT_END() |
1095 | }; | 1077 | }; |
1096 | 1078 | const char * const timechart_usage[] = { | |
1079 | "perf timechart [<options>] {record}", | ||
1080 | NULL | ||
1081 | }; | ||
1097 | 1082 | ||
1098 | int cmd_timechart(int argc, const char **argv, | ||
1099 | const char *prefix __maybe_unused) | ||
1100 | { | ||
1101 | argc = parse_options(argc, argv, options, timechart_usage, | 1083 | argc = parse_options(argc, argv, options, timechart_usage, |
1102 | PARSE_OPT_STOP_AT_NON_OPTION); | 1084 | PARSE_OPT_STOP_AT_NON_OPTION); |
1103 | 1085 | ||
@@ -1110,5 +1092,5 @@ int cmd_timechart(int argc, const char **argv, | |||
1110 | 1092 | ||
1111 | setup_pager(); | 1093 | setup_pager(); |
1112 | 1094 | ||
1113 | return __cmd_timechart(); | 1095 | return __cmd_timechart(input_name, output_name); |
1114 | } | 1096 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e434a16bb5ac..ff6db8086805 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
316 | hists__output_recalc_col_len(&top->sym_evsel->hists, | 316 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
317 | top->winsize.ws_row - 3); | 317 | top->winsize.ws_row - 3); |
318 | putchar('\n'); | 318 | putchar('\n'); |
319 | hists__fprintf(&top->sym_evsel->hists, NULL, false, false, | 319 | hists__fprintf(&top->sym_evsel->hists, false, |
320 | top->winsize.ws_row - 4 - printed, win_width, stdout); | 320 | top->winsize.ws_row - 4 - printed, win_width, stdout); |
321 | } | 321 | } |
322 | 322 | ||
@@ -1159,11 +1159,6 @@ setup: | |||
1159 | return 0; | 1159 | return 0; |
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | static const char * const top_usage[] = { | ||
1163 | "perf top [<options>]", | ||
1164 | NULL | ||
1165 | }; | ||
1166 | |||
1167 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1162 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1168 | { | 1163 | { |
1169 | struct perf_evsel *pos; | 1164 | struct perf_evsel *pos; |
@@ -1250,6 +1245,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1250 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), | 1245 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), |
1251 | OPT_END() | 1246 | OPT_END() |
1252 | }; | 1247 | }; |
1248 | const char * const top_usage[] = { | ||
1249 | "perf top [<options>]", | ||
1250 | NULL | ||
1251 | }; | ||
1253 | 1252 | ||
1254 | top.evlist = perf_evlist__new(NULL, NULL); | 1253 | top.evlist = perf_evlist__new(NULL, NULL); |
1255 | if (top.evlist == NULL) | 1254 | if (top.evlist == NULL) |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8f113dab8bf1..7aaee39f6774 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -56,6 +56,10 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
56 | { | 56 | { |
57 | char tp_name[128]; | 57 | char tp_name[128]; |
58 | struct syscall *sc; | 58 | struct syscall *sc; |
59 | const char *name = audit_syscall_to_name(id, trace->audit_machine); | ||
60 | |||
61 | if (name == NULL) | ||
62 | return -1; | ||
59 | 63 | ||
60 | if (id > trace->syscalls.max) { | 64 | if (id > trace->syscalls.max) { |
61 | struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); | 65 | struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); |
@@ -75,11 +79,8 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
75 | } | 79 | } |
76 | 80 | ||
77 | sc = trace->syscalls.table + id; | 81 | sc = trace->syscalls.table + id; |
78 | sc->name = audit_syscall_to_name(id, trace->audit_machine); | 82 | sc->name = name; |
79 | if (sc->name == NULL) | 83 | sc->fmt = syscall_fmt__find(sc->name); |
80 | return -1; | ||
81 | |||
82 | sc->fmt = syscall_fmt__find(sc->name); | ||
83 | 84 | ||
84 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 85 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
85 | sc->tp_format = event_format__new("syscalls", tp_name); | 86 | sc->tp_format = event_format__new("syscalls", tp_name); |
@@ -114,10 +115,85 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL | |||
114 | return printed; | 115 | return printed; |
115 | } | 116 | } |
116 | 117 | ||
118 | typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, | ||
119 | struct perf_sample *sample); | ||
120 | |||
121 | static struct syscall *trace__syscall_info(struct trace *trace, | ||
122 | struct perf_evsel *evsel, | ||
123 | struct perf_sample *sample) | ||
124 | { | ||
125 | int id = perf_evsel__intval(evsel, sample, "id"); | ||
126 | |||
127 | if (id < 0) { | ||
128 | printf("Invalid syscall %d id, skipping...\n", id); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
133 | trace__read_syscall_info(trace, id)) | ||
134 | goto out_cant_read; | ||
135 | |||
136 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
137 | goto out_cant_read; | ||
138 | |||
139 | return &trace->syscalls.table[id]; | ||
140 | |||
141 | out_cant_read: | ||
142 | printf("Problems reading syscall %d information\n", id); | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
146 | static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | ||
147 | struct perf_sample *sample) | ||
148 | { | ||
149 | void *args; | ||
150 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
151 | |||
152 | if (sc == NULL) | ||
153 | return -1; | ||
154 | |||
155 | args = perf_evsel__rawptr(evsel, sample, "args"); | ||
156 | if (args == NULL) { | ||
157 | printf("Problems reading syscall arguments\n"); | ||
158 | return -1; | ||
159 | } | ||
160 | |||
161 | printf("%s(", sc->name); | ||
162 | syscall__fprintf_args(sc, args, stdout); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | ||
168 | struct perf_sample *sample) | ||
169 | { | ||
170 | int ret; | ||
171 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
172 | |||
173 | if (sc == NULL) | ||
174 | return -1; | ||
175 | |||
176 | ret = perf_evsel__intval(evsel, sample, "ret"); | ||
177 | |||
178 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
179 | char bf[256]; | ||
180 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
181 | *e = audit_errno_to_name(-ret); | ||
182 | |||
183 | printf(") = -1 %s %s", e, emsg); | ||
184 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
185 | printf(") = 0 Timeout"); | ||
186 | else | ||
187 | printf(") = %d", ret); | ||
188 | |||
189 | putchar('\n'); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
117 | static int trace__run(struct trace *trace) | 193 | static int trace__run(struct trace *trace) |
118 | { | 194 | { |
119 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 195 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); |
120 | struct perf_evsel *evsel, *evsel_enter, *evsel_exit; | 196 | struct perf_evsel *evsel; |
121 | int err = -1, i, nr_events = 0, before; | 197 | int err = -1, i, nr_events = 0, before; |
122 | 198 | ||
123 | if (evlist == NULL) { | 199 | if (evlist == NULL) { |
@@ -125,22 +201,12 @@ static int trace__run(struct trace *trace) | |||
125 | goto out; | 201 | goto out; |
126 | } | 202 | } |
127 | 203 | ||
128 | evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0); | 204 | if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || |
129 | if (evsel_enter == NULL) { | 205 | perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { |
130 | printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n"); | 206 | printf("Couldn't read the raw_syscalls tracepoints information!\n"); |
131 | goto out_delete_evlist; | 207 | goto out_delete_evlist; |
132 | } | 208 | } |
133 | 209 | ||
134 | perf_evlist__add(evlist, evsel_enter); | ||
135 | |||
136 | evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1); | ||
137 | if (evsel_exit == NULL) { | ||
138 | printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n"); | ||
139 | goto out_delete_evlist; | ||
140 | } | ||
141 | |||
142 | perf_evlist__add(evlist, evsel_exit); | ||
143 | |||
144 | err = perf_evlist__create_maps(evlist, &trace->opts.target); | 210 | err = perf_evlist__create_maps(evlist, &trace->opts.target); |
145 | if (err < 0) { | 211 | if (err < 0) { |
146 | printf("Problems parsing the target to trace, check your options!\n"); | 212 | printf("Problems parsing the target to trace, check your options!\n"); |
@@ -170,9 +236,8 @@ again: | |||
170 | 236 | ||
171 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | 237 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { |
172 | const u32 type = event->header.type; | 238 | const u32 type = event->header.type; |
173 | struct syscall *sc; | 239 | tracepoint_handler handler; |
174 | struct perf_sample sample; | 240 | struct perf_sample sample; |
175 | int id; | ||
176 | 241 | ||
177 | ++nr_events; | 242 | ++nr_events; |
178 | 243 | ||
@@ -200,45 +265,18 @@ again: | |||
200 | continue; | 265 | continue; |
201 | } | 266 | } |
202 | 267 | ||
203 | id = perf_evsel__intval(evsel, &sample, "id"); | ||
204 | if (id < 0) { | ||
205 | printf("Invalid syscall %d id, skipping...\n", id); | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
210 | trace__read_syscall_info(trace, id)) | ||
211 | continue; | ||
212 | |||
213 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
214 | continue; | ||
215 | |||
216 | sc = &trace->syscalls.table[id]; | ||
217 | |||
218 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) | 268 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) |
219 | printf("%d ", sample.tid); | 269 | printf("%d ", sample.tid); |
220 | 270 | ||
221 | if (evsel == evsel_enter) { | 271 | if (sample.raw_data == NULL) { |
222 | void *args = perf_evsel__rawptr(evsel, &sample, "args"); | 272 | printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", |
223 | 273 | perf_evsel__name(evsel), sample.tid, | |
224 | printf("%s(", sc->name); | 274 | sample.cpu, sample.raw_size); |
225 | syscall__fprintf_args(sc, args, stdout); | 275 | continue; |
226 | } else if (evsel == evsel_exit) { | ||
227 | int ret = perf_evsel__intval(evsel, &sample, "ret"); | ||
228 | |||
229 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
230 | char bf[256]; | ||
231 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
232 | *e = audit_errno_to_name(-ret); | ||
233 | |||
234 | printf(") = -1 %s %s", e, emsg); | ||
235 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
236 | printf(") = 0 Timeout"); | ||
237 | else | ||
238 | printf(") = %d", ret); | ||
239 | |||
240 | putchar('\n'); | ||
241 | } | 276 | } |
277 | |||
278 | handler = evsel->handler.func; | ||
279 | handler(trace, evsel, &sample); | ||
242 | } | 280 | } |
243 | } | 281 | } |
244 | 282 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fc2f770e3027..6d50eb0b4251 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -48,14 +48,14 @@ static struct cmd_struct commands[] = { | |||
48 | { "version", cmd_version, 0 }, | 48 | { "version", cmd_version, 0 }, |
49 | { "script", cmd_script, 0 }, | 49 | { "script", cmd_script, 0 }, |
50 | { "sched", cmd_sched, 0 }, | 50 | { "sched", cmd_sched, 0 }, |
51 | #ifndef NO_LIBELF_SUPPORT | 51 | #ifdef LIBELF_SUPPORT |
52 | { "probe", cmd_probe, 0 }, | 52 | { "probe", cmd_probe, 0 }, |
53 | #endif | 53 | #endif |
54 | { "kmem", cmd_kmem, 0 }, | 54 | { "kmem", cmd_kmem, 0 }, |
55 | { "lock", cmd_lock, 0 }, | 55 | { "lock", cmd_lock, 0 }, |
56 | { "kvm", cmd_kvm, 0 }, | 56 | { "kvm", cmd_kvm, 0 }, |
57 | { "test", cmd_test, 0 }, | 57 | { "test", cmd_test, 0 }, |
58 | #ifndef NO_LIBAUDIT_SUPPORT | 58 | #ifdef LIBAUDIT_SUPPORT |
59 | { "trace", cmd_trace, 0 }, | 59 | { "trace", cmd_trace, 0 }, |
60 | #endif | 60 | #endif |
61 | { "inject", cmd_inject, 0 }, | 61 | { "inject", cmd_inject, 0 }, |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index a89cbbb61801..c50985eaec41 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -57,7 +57,7 @@ void get_term_dimensions(struct winsize *ws); | |||
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | #ifdef __sparc__ | 59 | #ifdef __sparc__ |
60 | #include "../../arch/sparc/include/asm/unistd.h" | 60 | #include "../../arch/sparc/include/uapi/asm/unistd.h" |
61 | #define rmb() asm volatile("":::"memory") | 61 | #define rmb() asm volatile("":::"memory") |
62 | #define cpu_relax() asm volatile("":::"memory") | 62 | #define cpu_relax() asm volatile("":::"memory") |
63 | #define CPUINFO_PROC "cpu" | 63 | #define CPUINFO_PROC "cpu" |
@@ -112,7 +112,7 @@ void get_term_dimensions(struct winsize *ws); | |||
112 | #include <sys/types.h> | 112 | #include <sys/types.h> |
113 | #include <sys/syscall.h> | 113 | #include <sys/syscall.h> |
114 | 114 | ||
115 | #include "../../include/linux/perf_event.h" | 115 | #include "../../include/uapi/linux/perf_event.h" |
116 | #include "util/types.h" | 116 | #include "util/types.h" |
117 | #include <stdbool.h> | 117 | #include <stdbool.h> |
118 | 118 | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a21f40bebbac..ef2f93ca7496 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -569,7 +569,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
569 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 569 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ |
570 | struct hist_entry *he) \ | 570 | struct hist_entry *he) \ |
571 | { \ | 571 | { \ |
572 | double percent = 100.0 * he->_field / hpp->total_period; \ | 572 | struct hists *hists = he->hists; \ |
573 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
573 | *(double *)hpp->ptr = percent; \ | 574 | *(double *)hpp->ptr = percent; \ |
574 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ | 575 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ |
575 | } | 576 | } |
@@ -584,7 +585,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
584 | 585 | ||
585 | void hist_browser__init_hpp(void) | 586 | void hist_browser__init_hpp(void) |
586 | { | 587 | { |
587 | perf_hpp__init(false, false); | 588 | perf_hpp__init(); |
588 | 589 | ||
589 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 590 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
590 | hist_browser__hpp_color_overhead; | 591 | hist_browser__hpp_color_overhead; |
@@ -609,6 +610,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
609 | char folded_sign = ' '; | 610 | char folded_sign = ' '; |
610 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 611 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
611 | off_t row_offset = entry->row_offset; | 612 | off_t row_offset = entry->row_offset; |
613 | bool first = true; | ||
612 | 614 | ||
613 | if (current_entry) { | 615 | if (current_entry) { |
614 | browser->he_selection = entry; | 616 | browser->he_selection = entry; |
@@ -624,7 +626,6 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
624 | struct perf_hpp hpp = { | 626 | struct perf_hpp hpp = { |
625 | .buf = s, | 627 | .buf = s, |
626 | .size = sizeof(s), | 628 | .size = sizeof(s), |
627 | .total_period = browser->hists->stats.total_period, | ||
628 | }; | 629 | }; |
629 | 630 | ||
630 | ui_browser__gotorc(&browser->b, row, 0); | 631 | ui_browser__gotorc(&browser->b, row, 0); |
@@ -633,10 +634,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
633 | if (!perf_hpp__format[i].cond) | 634 | if (!perf_hpp__format[i].cond) |
634 | continue; | 635 | continue; |
635 | 636 | ||
636 | if (i) { | 637 | if (!first) { |
637 | slsmg_printf(" "); | 638 | slsmg_printf(" "); |
638 | width -= 2; | 639 | width -= 2; |
639 | } | 640 | } |
641 | first = false; | ||
640 | 642 | ||
641 | if (perf_hpp__format[i].color) { | 643 | if (perf_hpp__format[i].color) { |
642 | hpp.ptr = &percent; | 644 | hpp.ptr = &percent; |
@@ -645,7 +647,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
645 | 647 | ||
646 | ui_browser__set_percent_color(&browser->b, percent, current_entry); | 648 | ui_browser__set_percent_color(&browser->b, percent, current_entry); |
647 | 649 | ||
648 | if (i == 0 && symbol_conf.use_callchain) { | 650 | if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { |
649 | slsmg_printf("%c ", folded_sign); | 651 | slsmg_printf("%c ", folded_sign); |
650 | width -= 2; | 652 | width -= 2; |
651 | } | 653 | } |
@@ -982,7 +984,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
982 | folded_sign = hist_entry__folded(he); | 984 | folded_sign = hist_entry__folded(he); |
983 | 985 | ||
984 | hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); | 986 | hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); |
985 | percent = (he->period * 100.0) / browser->hists->stats.total_period; | 987 | percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; |
986 | 988 | ||
987 | if (symbol_conf.use_callchain) | 989 | if (symbol_conf.use_callchain) |
988 | printed += fprintf(fp, "%c ", folded_sign); | 990 | printed += fprintf(fp, "%c ", folded_sign); |
@@ -990,10 +992,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
990 | printed += fprintf(fp, " %5.2f%%", percent); | 992 | printed += fprintf(fp, " %5.2f%%", percent); |
991 | 993 | ||
992 | if (symbol_conf.show_nr_samples) | 994 | if (symbol_conf.show_nr_samples) |
993 | printed += fprintf(fp, " %11u", he->nr_events); | 995 | printed += fprintf(fp, " %11u", he->stat.nr_events); |
994 | 996 | ||
995 | if (symbol_conf.show_total_period) | 997 | if (symbol_conf.show_total_period) |
996 | printed += fprintf(fp, " %12" PRIu64, he->period); | 998 | printed += fprintf(fp, " %12" PRIu64, he->stat.period); |
997 | 999 | ||
998 | printed += fprintf(fp, "%s\n", rtrim(s)); | 1000 | printed += fprintf(fp, "%s\n", rtrim(s)); |
999 | 1001 | ||
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 7ff99ec1d95e..4125c6284114 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
@@ -49,7 +49,8 @@ static const char *perf_gtk__get_percent_color(double percent) | |||
49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ |
50 | struct hist_entry *he) \ | 50 | struct hist_entry *he) \ |
51 | { \ | 51 | { \ |
52 | double percent = 100.0 * he->_field / hpp->total_period; \ | 52 | struct hists *hists = he->hists; \ |
53 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
53 | const char *markup; \ | 54 | const char *markup; \ |
54 | int ret = 0; \ | 55 | int ret = 0; \ |
55 | \ | 56 | \ |
@@ -73,7 +74,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
73 | 74 | ||
74 | void perf_gtk__init_hpp(void) | 75 | void perf_gtk__init_hpp(void) |
75 | { | 76 | { |
76 | perf_hpp__init(false, false); | 77 | perf_hpp__init(); |
77 | 78 | ||
78 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 79 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
79 | perf_gtk__hpp_color_overhead; | 80 | perf_gtk__hpp_color_overhead; |
@@ -102,7 +103,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
102 | struct perf_hpp hpp = { | 103 | struct perf_hpp hpp = { |
103 | .buf = s, | 104 | .buf = s, |
104 | .size = sizeof(s), | 105 | .size = sizeof(s), |
105 | .total_period = hists->stats.total_period, | ||
106 | }; | 106 | }; |
107 | 107 | ||
108 | nr_cols = 0; | 108 | nr_cols = 0; |
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 8aada5b3c04c..ccb046aac98b 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c | |||
@@ -116,7 +116,7 @@ struct perf_error_ops perf_gtk_eops = { | |||
116 | * FIXME: Functions below should be implemented properly. | 116 | * FIXME: Functions below should be implemented properly. |
117 | * For now, just add stubs for NO_NEWT=1 build. | 117 | * For now, just add stubs for NO_NEWT=1 build. |
118 | */ | 118 | */ |
119 | #ifdef NO_NEWT_SUPPORT | 119 | #ifndef NEWT_SUPPORT |
120 | void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, | 120 | void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, |
121 | const char *title __maybe_unused) | 121 | const char *title __maybe_unused) |
122 | { | 122 | { |
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index 2b667ee454c3..baa28a4d16b9 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h | |||
@@ -23,25 +23,25 @@ void ui_helpline__puts(const char *msg); | |||
23 | 23 | ||
24 | extern char ui_helpline__current[512]; | 24 | extern char ui_helpline__current[512]; |
25 | 25 | ||
26 | #ifdef NO_NEWT_SUPPORT | 26 | #ifdef NEWT_SUPPORT |
27 | extern char ui_helpline__last_msg[]; | ||
28 | int ui_helpline__show_help(const char *format, va_list ap); | ||
29 | #else | ||
27 | static inline int ui_helpline__show_help(const char *format __maybe_unused, | 30 | static inline int ui_helpline__show_help(const char *format __maybe_unused, |
28 | va_list ap __maybe_unused) | 31 | va_list ap __maybe_unused) |
29 | { | 32 | { |
30 | return 0; | 33 | return 0; |
31 | } | 34 | } |
32 | #else | 35 | #endif /* NEWT_SUPPORT */ |
33 | extern char ui_helpline__last_msg[]; | ||
34 | int ui_helpline__show_help(const char *format, va_list ap); | ||
35 | #endif /* NO_NEWT_SUPPORT */ | ||
36 | 36 | ||
37 | #ifdef NO_GTK2_SUPPORT | 37 | #ifdef GTK2_SUPPORT |
38 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
39 | #else | ||
38 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, | 40 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, |
39 | va_list ap __maybe_unused) | 41 | va_list ap __maybe_unused) |
40 | { | 42 | { |
41 | return 0; | 43 | return 0; |
42 | } | 44 | } |
43 | #else | 45 | #endif /* GTK2_SUPPORT */ |
44 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
45 | #endif /* NO_GTK2_SUPPORT */ | ||
46 | 46 | ||
47 | #endif /* _PERF_UI_HELPLINE_H_ */ | 47 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index e3f8cd46e7d7..f5a1e4f65263 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -8,9 +8,7 @@ | |||
8 | /* hist period print (hpp) functions */ | 8 | /* hist period print (hpp) functions */ |
9 | static int hpp__header_overhead(struct perf_hpp *hpp) | 9 | static int hpp__header_overhead(struct perf_hpp *hpp) |
10 | { | 10 | { |
11 | const char *fmt = hpp->ptr ? "Baseline" : "Overhead"; | 11 | return scnprintf(hpp->buf, hpp->size, "Overhead"); |
12 | |||
13 | return scnprintf(hpp->buf, hpp->size, fmt); | ||
14 | } | 12 | } |
15 | 13 | ||
16 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | 14 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) |
@@ -20,38 +18,18 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | |||
20 | 18 | ||
21 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 19 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) |
22 | { | 20 | { |
23 | double percent = 100.0 * he->period / hpp->total_period; | 21 | struct hists *hists = he->hists; |
24 | 22 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | |
25 | if (hpp->ptr) { | ||
26 | struct hists *old_hists = hpp->ptr; | ||
27 | u64 total_period = old_hists->stats.total_period; | ||
28 | u64 base_period = he->pair ? he->pair->period : 0; | ||
29 | |||
30 | if (total_period) | ||
31 | percent = 100.0 * base_period / total_period; | ||
32 | else | ||
33 | percent = 0.0; | ||
34 | } | ||
35 | 23 | ||
36 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 24 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
37 | } | 25 | } |
38 | 26 | ||
39 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 27 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) |
40 | { | 28 | { |
41 | double percent = 100.0 * he->period / hpp->total_period; | 29 | struct hists *hists = he->hists; |
30 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
42 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | 31 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; |
43 | 32 | ||
44 | if (hpp->ptr) { | ||
45 | struct hists *old_hists = hpp->ptr; | ||
46 | u64 total_period = old_hists->stats.total_period; | ||
47 | u64 base_period = he->pair ? he->pair->period : 0; | ||
48 | |||
49 | if (total_period) | ||
50 | percent = 100.0 * base_period / total_period; | ||
51 | else | ||
52 | percent = 0.0; | ||
53 | } | ||
54 | |||
55 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 33 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
56 | } | 34 | } |
57 | 35 | ||
@@ -69,13 +47,16 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | |||
69 | 47 | ||
70 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 48 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
71 | { | 49 | { |
72 | double percent = 100.0 * he->period_sys / hpp->total_period; | 50 | struct hists *hists = he->hists; |
51 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
52 | |||
73 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 53 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
74 | } | 54 | } |
75 | 55 | ||
76 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 56 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
77 | { | 57 | { |
78 | double percent = 100.0 * he->period_sys / hpp->total_period; | 58 | struct hists *hists = he->hists; |
59 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
79 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | 60 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
80 | 61 | ||
81 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 62 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
@@ -95,13 +76,16 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | |||
95 | 76 | ||
96 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 77 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
97 | { | 78 | { |
98 | double percent = 100.0 * he->period_us / hpp->total_period; | 79 | struct hists *hists = he->hists; |
80 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
81 | |||
99 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 82 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
100 | } | 83 | } |
101 | 84 | ||
102 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 85 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
103 | { | 86 | { |
104 | double percent = 100.0 * he->period_us / hpp->total_period; | 87 | struct hists *hists = he->hists; |
88 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
105 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | 89 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
106 | 90 | ||
107 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 91 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
@@ -120,14 +104,17 @@ static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) | |||
120 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, | 104 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, |
121 | struct hist_entry *he) | 105 | struct hist_entry *he) |
122 | { | 106 | { |
123 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 107 | struct hists *hists = he->hists; |
108 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
109 | |||
124 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 110 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
125 | } | 111 | } |
126 | 112 | ||
127 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, | 113 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, |
128 | struct hist_entry *he) | 114 | struct hist_entry *he) |
129 | { | 115 | { |
130 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 116 | struct hists *hists = he->hists; |
117 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
131 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 118 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
132 | 119 | ||
133 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 120 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
@@ -146,19 +133,63 @@ static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) | |||
146 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | 133 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, |
147 | struct hist_entry *he) | 134 | struct hist_entry *he) |
148 | { | 135 | { |
149 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 136 | struct hists *hists = he->hists; |
137 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | ||
138 | |||
150 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 139 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
151 | } | 140 | } |
152 | 141 | ||
153 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 142 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, |
154 | struct hist_entry *he) | 143 | struct hist_entry *he) |
155 | { | 144 | { |
156 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 145 | struct hists *hists = he->hists; |
146 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | ||
157 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 147 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
158 | 148 | ||
159 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 149 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
160 | } | 150 | } |
161 | 151 | ||
152 | static int hpp__header_baseline(struct perf_hpp *hpp) | ||
153 | { | ||
154 | return scnprintf(hpp->buf, hpp->size, "Baseline"); | ||
155 | } | ||
156 | |||
157 | static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) | ||
158 | { | ||
159 | return 8; | ||
160 | } | ||
161 | |||
162 | static double baseline_percent(struct hist_entry *he) | ||
163 | { | ||
164 | struct hist_entry *pair = he->pair; | ||
165 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
166 | double percent = 0.0; | ||
167 | |||
168 | if (pair) { | ||
169 | u64 total_period = pair_hists->stats.total_period; | ||
170 | u64 base_period = pair->stat.period; | ||
171 | |||
172 | percent = 100.0 * base_period / total_period; | ||
173 | } | ||
174 | |||
175 | return percent; | ||
176 | } | ||
177 | |||
178 | static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
179 | { | ||
180 | double percent = baseline_percent(he); | ||
181 | |||
182 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | ||
183 | } | ||
184 | |||
185 | static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
186 | { | ||
187 | double percent = baseline_percent(he); | ||
188 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
189 | |||
190 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
191 | } | ||
192 | |||
162 | static int hpp__header_samples(struct perf_hpp *hpp) | 193 | static int hpp__header_samples(struct perf_hpp *hpp) |
163 | { | 194 | { |
164 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; | 195 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; |
@@ -175,7 +206,7 @@ static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) | |||
175 | { | 206 | { |
176 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; | 207 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; |
177 | 208 | ||
178 | return scnprintf(hpp->buf, hpp->size, fmt, he->nr_events); | 209 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); |
179 | } | 210 | } |
180 | 211 | ||
181 | static int hpp__header_period(struct perf_hpp *hpp) | 212 | static int hpp__header_period(struct perf_hpp *hpp) |
@@ -194,7 +225,7 @@ static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) | |||
194 | { | 225 | { |
195 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | 226 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; |
196 | 227 | ||
197 | return scnprintf(hpp->buf, hpp->size, fmt, he->period); | 228 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); |
198 | } | 229 | } |
199 | 230 | ||
200 | static int hpp__header_delta(struct perf_hpp *hpp) | 231 | static int hpp__header_delta(struct perf_hpp *hpp) |
@@ -211,20 +242,22 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
211 | 242 | ||
212 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 243 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
213 | { | 244 | { |
214 | struct hists *pair_hists = hpp->ptr; | 245 | struct hist_entry *pair = he->pair; |
246 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
247 | struct hists *hists = he->hists; | ||
215 | u64 old_total, new_total; | 248 | u64 old_total, new_total; |
216 | double old_percent = 0, new_percent = 0; | 249 | double old_percent = 0, new_percent = 0; |
217 | double diff; | 250 | double diff; |
218 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 251 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
219 | char buf[32] = " "; | 252 | char buf[32] = " "; |
220 | 253 | ||
221 | old_total = pair_hists->stats.total_period; | 254 | old_total = pair_hists ? pair_hists->stats.total_period : 0; |
222 | if (old_total > 0 && he->pair) | 255 | if (old_total > 0 && pair) |
223 | old_percent = 100.0 * he->pair->period / old_total; | 256 | old_percent = 100.0 * pair->stat.period / old_total; |
224 | 257 | ||
225 | new_total = hpp->total_period; | 258 | new_total = hists->stats.total_period; |
226 | if (new_total > 0) | 259 | if (new_total > 0) |
227 | new_percent = 100.0 * he->period / new_total; | 260 | new_percent = 100.0 * he->stat.period / new_total; |
228 | 261 | ||
229 | diff = new_percent - old_percent; | 262 | diff = new_percent - old_percent; |
230 | if (fabs(diff) >= 0.01) | 263 | if (fabs(diff) >= 0.01) |
@@ -244,13 +277,15 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) | |||
244 | } | 277 | } |
245 | 278 | ||
246 | static int hpp__entry_displ(struct perf_hpp *hpp, | 279 | static int hpp__entry_displ(struct perf_hpp *hpp, |
247 | struct hist_entry *he __maybe_unused) | 280 | struct hist_entry *he) |
248 | { | 281 | { |
282 | struct hist_entry *pair = he->pair; | ||
283 | long displacement = pair ? pair->position - he->position : 0; | ||
249 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; | 284 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; |
250 | char buf[32] = " "; | 285 | char buf[32] = " "; |
251 | 286 | ||
252 | if (hpp->displacement) | 287 | if (displacement) |
253 | scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement); | 288 | scnprintf(buf, sizeof(buf), "%+4ld", displacement); |
254 | 289 | ||
255 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 290 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
256 | } | 291 | } |
@@ -267,6 +302,7 @@ static int hpp__entry_displ(struct perf_hpp *hpp, | |||
267 | .entry = hpp__entry_ ## _name | 302 | .entry = hpp__entry_ ## _name |
268 | 303 | ||
269 | struct perf_hpp_fmt perf_hpp__format[] = { | 304 | struct perf_hpp_fmt perf_hpp__format[] = { |
305 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | ||
270 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 306 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, |
271 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 307 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, |
272 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 308 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, |
@@ -281,7 +317,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { | |||
281 | #undef HPP__COLOR_PRINT_FNS | 317 | #undef HPP__COLOR_PRINT_FNS |
282 | #undef HPP__PRINT_FNS | 318 | #undef HPP__PRINT_FNS |
283 | 319 | ||
284 | void perf_hpp__init(bool need_pair, bool show_displacement) | 320 | void perf_hpp__init(void) |
285 | { | 321 | { |
286 | if (symbol_conf.show_cpu_utilization) { | 322 | if (symbol_conf.show_cpu_utilization) { |
287 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 323 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; |
@@ -298,13 +334,12 @@ void perf_hpp__init(bool need_pair, bool show_displacement) | |||
298 | 334 | ||
299 | if (symbol_conf.show_total_period) | 335 | if (symbol_conf.show_total_period) |
300 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 336 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; |
337 | } | ||
301 | 338 | ||
302 | if (need_pair) { | 339 | void perf_hpp__column_enable(unsigned col, bool enable) |
303 | perf_hpp__format[PERF_HPP__DELTA].cond = true; | 340 | { |
304 | 341 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | |
305 | if (show_displacement) | 342 | perf_hpp__format[col].cond = enable; |
306 | perf_hpp__format[PERF_HPP__DISPL].cond = true; | ||
307 | } | ||
308 | } | 343 | } |
309 | 344 | ||
310 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 345 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
@@ -319,6 +354,7 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
319 | const char *sep = symbol_conf.field_sep; | 354 | const char *sep = symbol_conf.field_sep; |
320 | char *start = hpp->buf; | 355 | char *start = hpp->buf; |
321 | int i, ret; | 356 | int i, ret; |
357 | bool first = true; | ||
322 | 358 | ||
323 | if (symbol_conf.exclude_other && !he->parent) | 359 | if (symbol_conf.exclude_other && !he->parent) |
324 | return 0; | 360 | return 0; |
@@ -327,9 +363,10 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
327 | if (!perf_hpp__format[i].cond) | 363 | if (!perf_hpp__format[i].cond) |
328 | continue; | 364 | continue; |
329 | 365 | ||
330 | if (!sep || i > 0) { | 366 | if (!sep || !first) { |
331 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 367 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
332 | advance_hpp(hpp, ret); | 368 | advance_hpp(hpp, ret); |
369 | first = false; | ||
333 | } | 370 | } |
334 | 371 | ||
335 | if (color && perf_hpp__format[i].color) | 372 | if (color && perf_hpp__format[i].color) |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index bd7d460f844c..ebb4cc107876 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
@@ -30,7 +30,7 @@ void setup_browser(bool fallback_to_pager) | |||
30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
31 | setup_pager(); | 31 | setup_pager(); |
32 | 32 | ||
33 | perf_hpp__init(false, false); | 33 | perf_hpp__init(); |
34 | break; | 34 | break; |
35 | } | 35 | } |
36 | } | 36 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 882461a42830..fbd4e32d0743 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -271,7 +271,7 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, | |||
271 | { | 271 | { |
272 | switch (callchain_param.mode) { | 272 | switch (callchain_param.mode) { |
273 | case CHAIN_GRAPH_REL: | 273 | case CHAIN_GRAPH_REL: |
274 | return callchain__fprintf_graph(fp, &he->sorted_chain, he->period, | 274 | return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, |
275 | left_margin); | 275 | left_margin); |
276 | break; | 276 | break; |
277 | case CHAIN_GRAPH_ABS: | 277 | case CHAIN_GRAPH_ABS: |
@@ -292,9 +292,10 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, | |||
292 | 292 | ||
293 | static size_t hist_entry__callchain_fprintf(struct hist_entry *he, | 293 | static size_t hist_entry__callchain_fprintf(struct hist_entry *he, |
294 | struct hists *hists, | 294 | struct hists *hists, |
295 | u64 total_period, FILE *fp) | 295 | FILE *fp) |
296 | { | 296 | { |
297 | int left_margin = 0; | 297 | int left_margin = 0; |
298 | u64 total_period = hists->stats.total_period; | ||
298 | 299 | ||
299 | if (sort__first_dimension == SORT_COMM) { | 300 | if (sort__first_dimension == SORT_COMM) { |
300 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, | 301 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, |
@@ -307,17 +308,13 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, | |||
307 | } | 308 | } |
308 | 309 | ||
309 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, | 310 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, |
310 | struct hists *hists, struct hists *pair_hists, | 311 | struct hists *hists, FILE *fp) |
311 | long displacement, u64 total_period, FILE *fp) | ||
312 | { | 312 | { |
313 | char bf[512]; | 313 | char bf[512]; |
314 | int ret; | 314 | int ret; |
315 | struct perf_hpp hpp = { | 315 | struct perf_hpp hpp = { |
316 | .buf = bf, | 316 | .buf = bf, |
317 | .size = size, | 317 | .size = size, |
318 | .total_period = total_period, | ||
319 | .displacement = displacement, | ||
320 | .ptr = pair_hists, | ||
321 | }; | 318 | }; |
322 | bool color = !symbol_conf.field_sep; | 319 | bool color = !symbol_conf.field_sep; |
323 | 320 | ||
@@ -330,22 +327,17 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
330 | ret = fprintf(fp, "%s\n", bf); | 327 | ret = fprintf(fp, "%s\n", bf); |
331 | 328 | ||
332 | if (symbol_conf.use_callchain) | 329 | if (symbol_conf.use_callchain) |
333 | ret += hist_entry__callchain_fprintf(he, hists, | 330 | ret += hist_entry__callchain_fprintf(he, hists, fp); |
334 | total_period, fp); | ||
335 | 331 | ||
336 | return ret; | 332 | return ret; |
337 | } | 333 | } |
338 | 334 | ||
339 | size_t hists__fprintf(struct hists *hists, struct hists *pair, | 335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
340 | bool show_displacement, bool show_header, int max_rows, | ||
341 | int max_cols, FILE *fp) | 336 | int max_cols, FILE *fp) |
342 | { | 337 | { |
343 | struct sort_entry *se; | 338 | struct sort_entry *se; |
344 | struct rb_node *nd; | 339 | struct rb_node *nd; |
345 | size_t ret = 0; | 340 | size_t ret = 0; |
346 | u64 total_period; | ||
347 | unsigned long position = 1; | ||
348 | long displacement = 0; | ||
349 | unsigned int width; | 341 | unsigned int width; |
350 | const char *sep = symbol_conf.field_sep; | 342 | const char *sep = symbol_conf.field_sep; |
351 | const char *col_width = symbol_conf.col_width_list_str; | 343 | const char *col_width = symbol_conf.col_width_list_str; |
@@ -354,8 +346,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
354 | struct perf_hpp dummy_hpp = { | 346 | struct perf_hpp dummy_hpp = { |
355 | .buf = bf, | 347 | .buf = bf, |
356 | .size = sizeof(bf), | 348 | .size = sizeof(bf), |
357 | .ptr = pair, | ||
358 | }; | 349 | }; |
350 | bool first = true; | ||
359 | 351 | ||
360 | init_rem_hits(); | 352 | init_rem_hits(); |
361 | 353 | ||
@@ -367,8 +359,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
367 | if (!perf_hpp__format[idx].cond) | 359 | if (!perf_hpp__format[idx].cond) |
368 | continue; | 360 | continue; |
369 | 361 | ||
370 | if (idx) | 362 | if (!first) |
371 | fprintf(fp, "%s", sep ?: " "); | 363 | fprintf(fp, "%s", sep ?: " "); |
364 | else | ||
365 | first = false; | ||
372 | 366 | ||
373 | perf_hpp__format[idx].header(&dummy_hpp); | 367 | perf_hpp__format[idx].header(&dummy_hpp); |
374 | fprintf(fp, "%s", bf); | 368 | fprintf(fp, "%s", bf); |
@@ -403,6 +397,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
403 | if (sep) | 397 | if (sep) |
404 | goto print_entries; | 398 | goto print_entries; |
405 | 399 | ||
400 | first = true; | ||
401 | |||
406 | fprintf(fp, "# "); | 402 | fprintf(fp, "# "); |
407 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | 403 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { |
408 | unsigned int i; | 404 | unsigned int i; |
@@ -410,8 +406,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
410 | if (!perf_hpp__format[idx].cond) | 406 | if (!perf_hpp__format[idx].cond) |
411 | continue; | 407 | continue; |
412 | 408 | ||
413 | if (idx) | 409 | if (!first) |
414 | fprintf(fp, "%s", sep ?: " "); | 410 | fprintf(fp, "%s", sep ?: " "); |
411 | else | ||
412 | first = false; | ||
415 | 413 | ||
416 | width = perf_hpp__format[idx].width(&dummy_hpp); | 414 | width = perf_hpp__format[idx].width(&dummy_hpp); |
417 | for (i = 0; i < width; i++) | 415 | for (i = 0; i < width; i++) |
@@ -441,24 +439,13 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
441 | goto out; | 439 | goto out; |
442 | 440 | ||
443 | print_entries: | 441 | print_entries: |
444 | total_period = hists->stats.total_period; | ||
445 | |||
446 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 442 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
447 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 443 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
448 | 444 | ||
449 | if (h->filtered) | 445 | if (h->filtered) |
450 | continue; | 446 | continue; |
451 | 447 | ||
452 | if (show_displacement) { | 448 | ret += hist_entry__fprintf(h, max_cols, hists, fp); |
453 | if (h->pair != NULL) | ||
454 | displacement = ((long)h->pair->position - | ||
455 | (long)position); | ||
456 | else | ||
457 | displacement = 0; | ||
458 | ++position; | ||
459 | } | ||
460 | ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement, | ||
461 | total_period, fp); | ||
462 | 449 | ||
463 | if (max_rows && ++nr_rows >= max_rows) | 450 | if (max_rows && ++nr_rows >= max_rows) |
464 | goto out; | 451 | goto out; |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9b5b21e7b032..39242dcee8f2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -138,7 +138,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
138 | bool print_lines, bool full_paths, int min_pcnt, | 138 | bool print_lines, bool full_paths, int min_pcnt, |
139 | int max_lines); | 139 | int max_lines); |
140 | 140 | ||
141 | #ifdef NO_NEWT_SUPPORT | 141 | #ifdef NEWT_SUPPORT |
142 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
143 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
144 | #else | ||
142 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 145 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
143 | struct map *map __maybe_unused, | 146 | struct map *map __maybe_unused, |
144 | int evidx __maybe_unused, | 147 | int evidx __maybe_unused, |
@@ -148,9 +151,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | |||
148 | { | 151 | { |
149 | return 0; | 152 | return 0; |
150 | } | 153 | } |
151 | #else | ||
152 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
153 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
154 | #endif | 154 | #endif |
155 | 155 | ||
156 | extern const char *disassembler_style; | 156 | extern const char *disassembler_style; |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index ab1769426541..2bd51370ad28 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -33,39 +33,41 @@ extern int pager_use_color; | |||
33 | 33 | ||
34 | extern int use_browser; | 34 | extern int use_browser; |
35 | 35 | ||
36 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 36 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) |
37 | static inline void setup_browser(bool fallback_to_pager) | ||
38 | { | ||
39 | if (fallback_to_pager) | ||
40 | setup_pager(); | ||
41 | } | ||
42 | static inline void exit_browser(bool wait_for_ok __maybe_unused) {} | ||
43 | #else | ||
44 | void setup_browser(bool fallback_to_pager); | 37 | void setup_browser(bool fallback_to_pager); |
45 | void exit_browser(bool wait_for_ok); | 38 | void exit_browser(bool wait_for_ok); |
46 | 39 | ||
47 | #ifdef NO_NEWT_SUPPORT | 40 | #ifdef NEWT_SUPPORT |
41 | int ui__init(void); | ||
42 | void ui__exit(bool wait_for_ok); | ||
43 | #else | ||
48 | static inline int ui__init(void) | 44 | static inline int ui__init(void) |
49 | { | 45 | { |
50 | return -1; | 46 | return -1; |
51 | } | 47 | } |
52 | static inline void ui__exit(bool wait_for_ok __maybe_unused) {} | 48 | static inline void ui__exit(bool wait_for_ok __maybe_unused) {} |
53 | #else | ||
54 | int ui__init(void); | ||
55 | void ui__exit(bool wait_for_ok); | ||
56 | #endif | 49 | #endif |
57 | 50 | ||
58 | #ifdef NO_GTK2_SUPPORT | 51 | #ifdef GTK2_SUPPORT |
52 | int perf_gtk__init(void); | ||
53 | void perf_gtk__exit(bool wait_for_ok); | ||
54 | #else | ||
59 | static inline int perf_gtk__init(void) | 55 | static inline int perf_gtk__init(void) |
60 | { | 56 | { |
61 | return -1; | 57 | return -1; |
62 | } | 58 | } |
63 | static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} | 59 | static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} |
64 | #else | ||
65 | int perf_gtk__init(void); | ||
66 | void perf_gtk__exit(bool wait_for_ok); | ||
67 | #endif | 60 | #endif |
68 | #endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | 61 | |
62 | #else /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
63 | |||
64 | static inline void setup_browser(bool fallback_to_pager) | ||
65 | { | ||
66 | if (fallback_to_pager) | ||
67 | setup_pager(); | ||
68 | } | ||
69 | static inline void exit_browser(bool wait_for_ok __maybe_unused) {} | ||
70 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
69 | 71 | ||
70 | char *alias_lookup(const char *alias); | 72 | char *alias_lookup(const char *alias); |
71 | int split_cmdline(char *cmdline, const char ***argv); | 73 | int split_cmdline(char *cmdline, const char ***argv); |
@@ -105,7 +107,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2 | |||
105 | extern char *perf_pathdup(const char *fmt, ...) | 107 | extern char *perf_pathdup(const char *fmt, ...) |
106 | __attribute__((format (printf, 1, 2))); | 108 | __attribute__((format (printf, 1, 2))); |
107 | 109 | ||
108 | #ifdef NO_STRLCPY | 110 | #ifndef HAVE_STRLCPY |
109 | extern size_t strlcpy(char *dest, const char *src, size_t size); | 111 | extern size_t strlcpy(char *dest, const char *src, size_t size); |
110 | #endif | 112 | #endif |
111 | 113 | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 66eb3828ceb5..03f830b48148 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -49,7 +49,7 @@ int dump_printf(const char *fmt, ...) | |||
49 | return ret; | 49 | return ret; |
50 | } | 50 | } |
51 | 51 | ||
52 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 52 | #if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) |
53 | int ui__warning(const char *format, ...) | 53 | int ui__warning(const char *format, ...) |
54 | { | 54 | { |
55 | va_list args; | 55 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index bb2e7d1007ab..dec98750b484 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -15,7 +15,14 @@ void trace_event(union perf_event *event); | |||
15 | struct ui_progress; | 15 | struct ui_progress; |
16 | struct perf_error_ops; | 16 | struct perf_error_ops; |
17 | 17 | ||
18 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 18 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) |
19 | |||
20 | #include "../ui/progress.h" | ||
21 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
22 | #include "../ui/util.h" | ||
23 | |||
24 | #else | ||
25 | |||
19 | static inline void ui_progress__update(u64 curr __maybe_unused, | 26 | static inline void ui_progress__update(u64 curr __maybe_unused, |
20 | u64 total __maybe_unused, | 27 | u64 total __maybe_unused, |
21 | const char *title __maybe_unused) {} | 28 | const char *title __maybe_unused) {} |
@@ -34,13 +41,7 @@ perf_error__unregister(struct perf_error_ops *eops __maybe_unused) | |||
34 | return 0; | 41 | return 0; |
35 | } | 42 | } |
36 | 43 | ||
37 | #else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | 44 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ |
38 | |||
39 | #include "../ui/progress.h" | ||
40 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
41 | #include "../ui/util.h" | ||
42 | |||
43 | #endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | ||
44 | 45 | ||
45 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 46 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
46 | int ui__error_paranoid(void); | 47 | int ui__error_paranoid(void); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ae89686102f4..186b87730396 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -154,8 +154,8 @@ error: | |||
154 | return -ENOMEM; | 154 | return -ENOMEM; |
155 | } | 155 | } |
156 | 156 | ||
157 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | 157 | static int perf_evlist__add_attrs(struct perf_evlist *evlist, |
158 | struct perf_event_attr *attrs, size_t nr_attrs) | 158 | struct perf_event_attr *attrs, size_t nr_attrs) |
159 | { | 159 | { |
160 | struct perf_evsel *evsel, *n; | 160 | struct perf_evsel *evsel, *n; |
161 | LIST_HEAD(head); | 161 | LIST_HEAD(head); |
@@ -189,60 +189,6 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | |||
189 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); | 189 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); |
190 | } | 190 | } |
191 | 191 | ||
192 | static int trace_event__id(const char *evname) | ||
193 | { | ||
194 | char *filename, *colon; | ||
195 | int err = -1, fd; | ||
196 | |||
197 | if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) | ||
198 | return -1; | ||
199 | |||
200 | colon = strrchr(filename, ':'); | ||
201 | if (colon != NULL) | ||
202 | *colon = '/'; | ||
203 | |||
204 | fd = open(filename, O_RDONLY); | ||
205 | if (fd >= 0) { | ||
206 | char id[16]; | ||
207 | if (read(fd, id, sizeof(id)) > 0) | ||
208 | err = atoi(id); | ||
209 | close(fd); | ||
210 | } | ||
211 | |||
212 | free(filename); | ||
213 | return err; | ||
214 | } | ||
215 | |||
216 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | ||
217 | const char *tracepoints[], | ||
218 | size_t nr_tracepoints) | ||
219 | { | ||
220 | int err; | ||
221 | size_t i; | ||
222 | struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); | ||
223 | |||
224 | if (attrs == NULL) | ||
225 | return -1; | ||
226 | |||
227 | for (i = 0; i < nr_tracepoints; i++) { | ||
228 | err = trace_event__id(tracepoints[i]); | ||
229 | |||
230 | if (err < 0) | ||
231 | goto out_free_attrs; | ||
232 | |||
233 | attrs[i].type = PERF_TYPE_TRACEPOINT; | ||
234 | attrs[i].config = err; | ||
235 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | ||
236 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); | ||
237 | attrs[i].sample_period = 1; | ||
238 | } | ||
239 | |||
240 | err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); | ||
241 | out_free_attrs: | ||
242 | free(attrs); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | struct perf_evsel * | 192 | struct perf_evsel * |
247 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | 193 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) |
248 | { | 194 | { |
@@ -257,32 +203,18 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | |||
257 | return NULL; | 203 | return NULL; |
258 | } | 204 | } |
259 | 205 | ||
260 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | 206 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
261 | const struct perf_evsel_str_handler *assocs, | 207 | const char *sys, const char *name, void *handler) |
262 | size_t nr_assocs) | ||
263 | { | 208 | { |
264 | struct perf_evsel *evsel; | 209 | struct perf_evsel *evsel; |
265 | int err; | ||
266 | size_t i; | ||
267 | |||
268 | for (i = 0; i < nr_assocs; i++) { | ||
269 | err = trace_event__id(assocs[i].name); | ||
270 | if (err < 0) | ||
271 | goto out; | ||
272 | |||
273 | evsel = perf_evlist__find_tracepoint_by_id(evlist, err); | ||
274 | if (evsel == NULL) | ||
275 | continue; | ||
276 | 210 | ||
277 | err = -EEXIST; | 211 | evsel = perf_evsel__newtp(sys, name, evlist->nr_entries); |
278 | if (evsel->handler.func != NULL) | 212 | if (evsel == NULL) |
279 | goto out; | 213 | return -1; |
280 | evsel->handler.func = assocs[i].handler; | ||
281 | } | ||
282 | 214 | ||
283 | err = 0; | 215 | evsel->handler.func = handler; |
284 | out: | 216 | perf_evlist__add(evlist, evsel); |
285 | return err; | 217 | return 0; |
286 | } | 218 | } |
287 | 219 | ||
288 | void perf_evlist__disable(struct perf_evlist *evlist) | 220 | void perf_evlist__disable(struct perf_evlist *evlist) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3f1fb66be022..56003f779e60 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -51,26 +51,14 @@ void perf_evlist__delete(struct perf_evlist *evlist); | |||
51 | 51 | ||
52 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); | 52 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); |
53 | int perf_evlist__add_default(struct perf_evlist *evlist); | 53 | int perf_evlist__add_default(struct perf_evlist *evlist); |
54 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | ||
55 | struct perf_event_attr *attrs, size_t nr_attrs); | ||
56 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | 54 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, |
57 | struct perf_event_attr *attrs, size_t nr_attrs); | 55 | struct perf_event_attr *attrs, size_t nr_attrs); |
58 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | 56 | |
59 | const char *tracepoints[], size_t nr_tracepoints); | ||
60 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | ||
61 | const struct perf_evsel_str_handler *assocs, | ||
62 | size_t nr_assocs); | ||
63 | |||
64 | #define perf_evlist__add_attrs_array(evlist, array) \ | ||
65 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) | ||
66 | #define perf_evlist__add_default_attrs(evlist, array) \ | 57 | #define perf_evlist__add_default_attrs(evlist, array) \ |
67 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) | 58 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) |
68 | 59 | ||
69 | #define perf_evlist__add_tracepoints_array(evlist, array) \ | 60 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
70 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) | 61 | const char *sys, const char *name, void *handler); |
71 | |||
72 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | ||
73 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | ||
74 | 62 | ||
75 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 63 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
76 | 64 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ffdd94e9c9c3..618d41140abd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "thread_map.h" | 19 | #include "thread_map.h" |
20 | #include "target.h" | 20 | #include "target.h" |
21 | #include "../../../include/linux/hw_breakpoint.h" | 21 | #include "../../../include/linux/hw_breakpoint.h" |
22 | #include "../../include/linux/perf_event.h" | 22 | #include "../../../include/uapi/linux/perf_event.h" |
23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
24 | 24 | ||
25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3ead0d59c03d..6f94d6dea00f 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "../../../include/linux/perf_event.h" | 6 | #include "../../../include/uapi/linux/perf_event.h" |
7 | #include "types.h" | 7 | #include "types.h" |
8 | #include "xyarray.h" | 8 | #include "xyarray.h" |
9 | #include "cgroup.h" | 9 | #include "cgroup.h" |
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh index 389590c1ad21..3ac38031d534 100755 --- a/tools/perf/util/generate-cmdlist.sh +++ b/tools/perf/util/generate-cmdlist.sh | |||
@@ -22,7 +22,7 @@ do | |||
22 | }' "Documentation/perf-$cmd.txt" | 22 | }' "Documentation/perf-$cmd.txt" |
23 | done | 23 | done |
24 | 24 | ||
25 | echo "#ifndef NO_LIBELF_SUPPORT" | 25 | echo "#ifdef LIBELF_SUPPORT" |
26 | sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | | 26 | sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | |
27 | sort | | 27 | sort | |
28 | while read cmd | 28 | while read cmd |
@@ -35,5 +35,5 @@ do | |||
35 | p | 35 | p |
36 | }' "Documentation/perf-$cmd.txt" | 36 | }' "Documentation/perf-$cmd.txt" |
37 | done | 37 | done |
38 | echo "#endif /* NO_LIBELF_SUPPORT */" | 38 | echo "#endif /* LIBELF_SUPPORT */" |
39 | echo "};" | 39 | echo "};" |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 99bdd3abce59..879d215cdac9 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_HEADER_H | 1 | #ifndef __PERF_HEADER_H |
2 | #define __PERF_HEADER_H | 2 | #define __PERF_HEADER_H |
3 | 3 | ||
4 | #include "../../../include/linux/perf_event.h" | 4 | #include "../../../include/uapi/linux/perf_event.h" |
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include "types.h" | 7 | #include "types.h" |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 236bc9d98ff2..277947a669b2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -135,31 +135,47 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he, | |||
135 | { | 135 | { |
136 | switch (cpumode) { | 136 | switch (cpumode) { |
137 | case PERF_RECORD_MISC_KERNEL: | 137 | case PERF_RECORD_MISC_KERNEL: |
138 | he->period_sys += period; | 138 | he->stat.period_sys += period; |
139 | break; | 139 | break; |
140 | case PERF_RECORD_MISC_USER: | 140 | case PERF_RECORD_MISC_USER: |
141 | he->period_us += period; | 141 | he->stat.period_us += period; |
142 | break; | 142 | break; |
143 | case PERF_RECORD_MISC_GUEST_KERNEL: | 143 | case PERF_RECORD_MISC_GUEST_KERNEL: |
144 | he->period_guest_sys += period; | 144 | he->stat.period_guest_sys += period; |
145 | break; | 145 | break; |
146 | case PERF_RECORD_MISC_GUEST_USER: | 146 | case PERF_RECORD_MISC_GUEST_USER: |
147 | he->period_guest_us += period; | 147 | he->stat.period_guest_us += period; |
148 | break; | 148 | break; |
149 | default: | 149 | default: |
150 | break; | 150 | break; |
151 | } | 151 | } |
152 | } | 152 | } |
153 | 153 | ||
154 | static void he_stat__add_period(struct he_stat *he_stat, u64 period) | ||
155 | { | ||
156 | he_stat->period += period; | ||
157 | he_stat->nr_events += 1; | ||
158 | } | ||
159 | |||
160 | static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) | ||
161 | { | ||
162 | dest->period += src->period; | ||
163 | dest->period_sys += src->period_sys; | ||
164 | dest->period_us += src->period_us; | ||
165 | dest->period_guest_sys += src->period_guest_sys; | ||
166 | dest->period_guest_us += src->period_guest_us; | ||
167 | dest->nr_events += src->nr_events; | ||
168 | } | ||
169 | |||
154 | static void hist_entry__decay(struct hist_entry *he) | 170 | static void hist_entry__decay(struct hist_entry *he) |
155 | { | 171 | { |
156 | he->period = (he->period * 7) / 8; | 172 | he->stat.period = (he->stat.period * 7) / 8; |
157 | he->nr_events = (he->nr_events * 7) / 8; | 173 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; |
158 | } | 174 | } |
159 | 175 | ||
160 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | 176 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) |
161 | { | 177 | { |
162 | u64 prev_period = he->period; | 178 | u64 prev_period = he->stat.period; |
163 | 179 | ||
164 | if (prev_period == 0) | 180 | if (prev_period == 0) |
165 | return true; | 181 | return true; |
@@ -167,9 +183,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
167 | hist_entry__decay(he); | 183 | hist_entry__decay(he); |
168 | 184 | ||
169 | if (!he->filtered) | 185 | if (!he->filtered) |
170 | hists->stats.total_period -= prev_period - he->period; | 186 | hists->stats.total_period -= prev_period - he->stat.period; |
171 | 187 | ||
172 | return he->period == 0; | 188 | return he->stat.period == 0; |
173 | } | 189 | } |
174 | 190 | ||
175 | static void __hists__decay_entries(struct hists *hists, bool zap_user, | 191 | static void __hists__decay_entries(struct hists *hists, bool zap_user, |
@@ -223,7 +239,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
223 | 239 | ||
224 | if (he != NULL) { | 240 | if (he != NULL) { |
225 | *he = *template; | 241 | *he = *template; |
226 | he->nr_events = 1; | 242 | |
227 | if (he->ms.map) | 243 | if (he->ms.map) |
228 | he->ms.map->referenced = true; | 244 | he->ms.map->referenced = true; |
229 | if (symbol_conf.use_callchain) | 245 | if (symbol_conf.use_callchain) |
@@ -238,7 +254,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) | |||
238 | if (!h->filtered) { | 254 | if (!h->filtered) { |
239 | hists__calc_col_len(hists, h); | 255 | hists__calc_col_len(hists, h); |
240 | ++hists->nr_entries; | 256 | ++hists->nr_entries; |
241 | hists->stats.total_period += h->period; | 257 | hists->stats.total_period += h->stat.period; |
242 | } | 258 | } |
243 | } | 259 | } |
244 | 260 | ||
@@ -270,8 +286,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
270 | cmp = hist_entry__cmp(entry, he); | 286 | cmp = hist_entry__cmp(entry, he); |
271 | 287 | ||
272 | if (!cmp) { | 288 | if (!cmp) { |
273 | he->period += period; | 289 | he_stat__add_period(&he->stat, period); |
274 | ++he->nr_events; | ||
275 | 290 | ||
276 | /* If the map of an existing hist_entry has | 291 | /* If the map of an existing hist_entry has |
277 | * become out-of-date due to an exec() or | 292 | * become out-of-date due to an exec() or |
@@ -321,10 +336,14 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, | |||
321 | .cpu = al->cpu, | 336 | .cpu = al->cpu, |
322 | .ip = bi->to.addr, | 337 | .ip = bi->to.addr, |
323 | .level = al->level, | 338 | .level = al->level, |
324 | .period = period, | 339 | .stat = { |
340 | .period = period, | ||
341 | .nr_events = 1, | ||
342 | }, | ||
325 | .parent = sym_parent, | 343 | .parent = sym_parent, |
326 | .filtered = symbol__parent_filter(sym_parent), | 344 | .filtered = symbol__parent_filter(sym_parent), |
327 | .branch_info = bi, | 345 | .branch_info = bi, |
346 | .hists = self, | ||
328 | }; | 347 | }; |
329 | 348 | ||
330 | return add_hist_entry(self, &entry, al, period); | 349 | return add_hist_entry(self, &entry, al, period); |
@@ -343,9 +362,13 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
343 | .cpu = al->cpu, | 362 | .cpu = al->cpu, |
344 | .ip = al->addr, | 363 | .ip = al->addr, |
345 | .level = al->level, | 364 | .level = al->level, |
346 | .period = period, | 365 | .stat = { |
366 | .period = period, | ||
367 | .nr_events = 1, | ||
368 | }, | ||
347 | .parent = sym_parent, | 369 | .parent = sym_parent, |
348 | .filtered = symbol__parent_filter(sym_parent), | 370 | .filtered = symbol__parent_filter(sym_parent), |
371 | .hists = self, | ||
349 | }; | 372 | }; |
350 | 373 | ||
351 | return add_hist_entry(self, &entry, al, period); | 374 | return add_hist_entry(self, &entry, al, period); |
@@ -410,12 +433,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
410 | cmp = hist_entry__collapse(iter, he); | 433 | cmp = hist_entry__collapse(iter, he); |
411 | 434 | ||
412 | if (!cmp) { | 435 | if (!cmp) { |
413 | iter->period += he->period; | 436 | he_stat__add_stat(&iter->stat, &he->stat); |
414 | iter->period_sys += he->period_sys; | ||
415 | iter->period_us += he->period_us; | ||
416 | iter->period_guest_sys += he->period_guest_sys; | ||
417 | iter->period_guest_us += he->period_guest_us; | ||
418 | iter->nr_events += he->nr_events; | ||
419 | 437 | ||
420 | if (symbol_conf.use_callchain) { | 438 | if (symbol_conf.use_callchain) { |
421 | callchain_cursor_reset(&callchain_cursor); | 439 | callchain_cursor_reset(&callchain_cursor); |
@@ -518,7 +536,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
518 | parent = *p; | 536 | parent = *p; |
519 | iter = rb_entry(parent, struct hist_entry, rb_node); | 537 | iter = rb_entry(parent, struct hist_entry, rb_node); |
520 | 538 | ||
521 | if (he->period > iter->period) | 539 | if (he->stat.period > iter->stat.period) |
522 | p = &(*p)->rb_left; | 540 | p = &(*p)->rb_left; |
523 | else | 541 | else |
524 | p = &(*p)->rb_right; | 542 | p = &(*p)->rb_right; |
@@ -579,8 +597,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h | |||
579 | if (h->ms.unfolded) | 597 | if (h->ms.unfolded) |
580 | hists->nr_entries += h->nr_rows; | 598 | hists->nr_entries += h->nr_rows; |
581 | h->row_offset = 0; | 599 | h->row_offset = 0; |
582 | hists->stats.total_period += h->period; | 600 | hists->stats.total_period += h->stat.period; |
583 | hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; | 601 | hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events; |
584 | 602 | ||
585 | hists__calc_col_len(hists, h); | 603 | hists__calc_col_len(hists, h); |
586 | } | 604 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f011ad4756e8..66cb31fe81d2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -98,9 +98,8 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows); | |||
98 | void hists__inc_nr_events(struct hists *self, u32 type); | 98 | void hists__inc_nr_events(struct hists *self, u32 type); |
99 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 99 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); |
100 | 100 | ||
101 | size_t hists__fprintf(struct hists *self, struct hists *pair, | 101 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, |
102 | bool show_displacement, bool show_header, | 102 | int max_cols, FILE *fp); |
103 | int max_rows, int max_cols, FILE *fp); | ||
104 | 103 | ||
105 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); | 104 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); |
106 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); | 105 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); |
@@ -118,9 +117,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); | |||
118 | struct perf_hpp { | 117 | struct perf_hpp { |
119 | char *buf; | 118 | char *buf; |
120 | size_t size; | 119 | size_t size; |
121 | u64 total_period; | ||
122 | const char *sep; | 120 | const char *sep; |
123 | long displacement; | ||
124 | void *ptr; | 121 | void *ptr; |
125 | }; | 122 | }; |
126 | 123 | ||
@@ -135,6 +132,7 @@ struct perf_hpp_fmt { | |||
135 | extern struct perf_hpp_fmt perf_hpp__format[]; | 132 | extern struct perf_hpp_fmt perf_hpp__format[]; |
136 | 133 | ||
137 | enum { | 134 | enum { |
135 | PERF_HPP__BASELINE, | ||
138 | PERF_HPP__OVERHEAD, | 136 | PERF_HPP__OVERHEAD, |
139 | PERF_HPP__OVERHEAD_SYS, | 137 | PERF_HPP__OVERHEAD_SYS, |
140 | PERF_HPP__OVERHEAD_US, | 138 | PERF_HPP__OVERHEAD_US, |
@@ -148,13 +146,22 @@ enum { | |||
148 | PERF_HPP__MAX_INDEX | 146 | PERF_HPP__MAX_INDEX |
149 | }; | 147 | }; |
150 | 148 | ||
151 | void perf_hpp__init(bool need_pair, bool show_displacement); | 149 | void perf_hpp__init(void); |
150 | void perf_hpp__column_enable(unsigned col, bool enable); | ||
152 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | 151 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, |
153 | bool color); | 152 | bool color); |
154 | 153 | ||
155 | struct perf_evlist; | 154 | struct perf_evlist; |
156 | 155 | ||
157 | #ifdef NO_NEWT_SUPPORT | 156 | #ifdef NEWT_SUPPORT |
157 | #include "../ui/keysyms.h" | ||
158 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | ||
159 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
160 | |||
161 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | ||
162 | void(*timer)(void *arg), void *arg, | ||
163 | int refresh); | ||
164 | #else | ||
158 | static inline | 165 | static inline |
159 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | 166 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, |
160 | const char *help __maybe_unused, | 167 | const char *help __maybe_unused, |
@@ -177,17 +184,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self | |||
177 | } | 184 | } |
178 | #define K_LEFT -1 | 185 | #define K_LEFT -1 |
179 | #define K_RIGHT -2 | 186 | #define K_RIGHT -2 |
180 | #else | 187 | #endif |
181 | #include "../ui/keysyms.h" | ||
182 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | ||
183 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
184 | 188 | ||
185 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 189 | #ifdef GTK2_SUPPORT |
190 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, | ||
186 | void(*timer)(void *arg), void *arg, | 191 | void(*timer)(void *arg), void *arg, |
187 | int refresh); | 192 | int refresh); |
188 | #endif | 193 | #else |
189 | |||
190 | #ifdef NO_GTK2_SUPPORT | ||
191 | static inline | 194 | static inline |
192 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | 195 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, |
193 | const char *help __maybe_unused, | 196 | const char *help __maybe_unused, |
@@ -197,11 +200,6 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
197 | { | 200 | { |
198 | return 0; | 201 | return 0; |
199 | } | 202 | } |
200 | |||
201 | #else | ||
202 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, | ||
203 | void(*timer)(void *arg), void *arg, | ||
204 | int refresh); | ||
205 | #endif | 203 | #endif |
206 | 204 | ||
207 | unsigned int hists__sort_list_width(struct hists *self); | 205 | unsigned int hists__sort_list_width(struct hists *self); |
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h index b722abe3a626..2a9bdc066307 100644 --- a/tools/perf/util/include/asm/byteorder.h +++ b/tools/perf/util/include/asm/byteorder.h | |||
@@ -1,2 +1,2 @@ | |||
1 | #include <asm/types.h> | 1 | #include <asm/types.h> |
2 | #include "../../../../include/linux/swab.h" | 2 | #include "../../../../include/uapi/linux/swab.h" |
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h index 1b476c9ae649..c10a35e1afb8 100644 --- a/tools/perf/util/include/linux/const.h +++ b/tools/perf/util/include/linux/const.h | |||
@@ -1 +1 @@ | |||
#include "../../../../include/linux/const.h" | #include "../../../../include/uapi/linux/const.h" | ||
diff --git a/tools/perf/util/include/linux/rbtree_augmented.h b/tools/perf/util/include/linux/rbtree_augmented.h new file mode 100644 index 000000000000..9d6fcdf1788b --- /dev/null +++ b/tools/perf/util/include/linux/rbtree_augmented.h | |||
@@ -0,0 +1,2 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include "../../../../include/linux/rbtree_augmented.h" | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ead5316b3f89..6109fa4d14cd 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -162,7 +162,7 @@ int map__load(struct map *self, symbol_filter_t filter) | |||
162 | pr_warning(", continuing without symbols\n"); | 162 | pr_warning(", continuing without symbols\n"); |
163 | return -1; | 163 | return -1; |
164 | } else if (nr == 0) { | 164 | } else if (nr == 0) { |
165 | #ifndef NO_LIBELF_SUPPORT | 165 | #ifdef LIBELF_SUPPORT |
166 | const size_t len = strlen(name); | 166 | const size_t len = strlen(name); |
167 | const size_t real_len = len - sizeof(DSO__DELETED); | 167 | const size_t real_len = len - sizeof(DSO__DELETED); |
168 | 168 | ||
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index 28c18d1d52c3..516ecd9ddd6e 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -513,7 +513,8 @@ static int test__group1(struct perf_evlist *evlist) | |||
513 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 513 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
514 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 514 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
515 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 515 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
516 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 516 | /* use of precise requires exclude_guest */ |
517 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
517 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 518 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
518 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 519 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
519 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 520 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -599,7 +600,8 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
599 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | 600 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); |
600 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | 601 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); |
601 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 602 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
602 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 603 | /* use of precise requires exclude_guest */ |
604 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
603 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 605 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
604 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); | 606 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); |
605 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 607 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -662,7 +664,8 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
662 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 664 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
663 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 665 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
664 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 666 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
665 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 667 | /* use of precise requires exclude_guest */ |
668 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
666 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 669 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
667 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); | 670 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); |
668 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 671 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
@@ -676,7 +679,8 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
676 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | 679 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); |
677 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | 680 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); |
678 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 681 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
679 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 682 | /* use of precise requires exclude_guest */ |
683 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
680 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 684 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
681 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 685 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
682 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 686 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index aed38e4b9dfa..75c7b0fca6d9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -690,6 +690,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
690 | eH = 0; | 690 | eH = 0; |
691 | } else if (*str == 'p') { | 691 | } else if (*str == 'p') { |
692 | precise++; | 692 | precise++; |
693 | /* use of precise requires exclude_guest */ | ||
694 | if (!exclude_GH) | ||
695 | eG = 1; | ||
693 | } else | 696 | } else |
694 | break; | 697 | break; |
695 | 698 | ||
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index c356e443448d..839230ceb18b 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include <linux/list.h> | 7 | #include <linux/list.h> |
8 | #include <stdbool.h> | 8 | #include <stdbool.h> |
9 | #include "types.h" | 9 | #include "types.h" |
10 | #include "../../../include/linux/perf_event.h" | 10 | #include "../../../include/uapi/linux/perf_event.h" |
11 | #include "types.h" | 11 | #include "types.h" |
12 | 12 | ||
13 | struct list_head; | 13 | struct list_head; |
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 443fc116512b..2bc9e70df7e2 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -384,6 +384,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
384 | return usage_with_options_internal(usagestr, options, 1); | 384 | return usage_with_options_internal(usagestr, options, 1); |
385 | if (internal_help && !strcmp(arg + 2, "help")) | 385 | if (internal_help && !strcmp(arg + 2, "help")) |
386 | return parse_options_usage(usagestr, options); | 386 | return parse_options_usage(usagestr, options); |
387 | if (!strcmp(arg + 2, "list-opts")) | ||
388 | return PARSE_OPT_LIST; | ||
387 | switch (parse_long_opt(ctx, arg + 2, options)) { | 389 | switch (parse_long_opt(ctx, arg + 2, options)) { |
388 | case -1: | 390 | case -1: |
389 | return parse_options_usage(usagestr, options); | 391 | return parse_options_usage(usagestr, options); |
@@ -422,6 +424,12 @@ int parse_options(int argc, const char **argv, const struct option *options, | |||
422 | exit(129); | 424 | exit(129); |
423 | case PARSE_OPT_DONE: | 425 | case PARSE_OPT_DONE: |
424 | break; | 426 | break; |
427 | case PARSE_OPT_LIST: | ||
428 | while (options->type != OPTION_END) { | ||
429 | printf("--%s ", options->long_name); | ||
430 | options++; | ||
431 | } | ||
432 | exit(130); | ||
425 | default: /* PARSE_OPT_UNKNOWN */ | 433 | default: /* PARSE_OPT_UNKNOWN */ |
426 | if (ctx.argv[0][1] == '-') { | 434 | if (ctx.argv[0][1] == '-') { |
427 | error("unknown option `%s'", ctx.argv[0] + 2); | 435 | error("unknown option `%s'", ctx.argv[0] + 2); |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index abc31a1dac1a..7bb5999940ca 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -140,6 +140,7 @@ extern NORETURN void usage_with_options(const char * const *usagestr, | |||
140 | enum { | 140 | enum { |
141 | PARSE_OPT_HELP = -1, | 141 | PARSE_OPT_HELP = -1, |
142 | PARSE_OPT_DONE, | 142 | PARSE_OPT_DONE, |
143 | PARSE_OPT_LIST, | ||
143 | PARSE_OPT_UNKNOWN, | 144 | PARSE_OPT_UNKNOWN, |
144 | }; | 145 | }; |
145 | 146 | ||
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index bd7497711424..a8c49548ca48 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c | |||
@@ -22,7 +22,7 @@ static const char *get_perf_dir(void) | |||
22 | return "."; | 22 | return "."; |
23 | } | 23 | } |
24 | 24 | ||
25 | #ifdef NO_STRLCPY | 25 | #ifndef HAVE_STRLCPY |
26 | size_t strlcpy(char *dest, const char *src, size_t size) | 26 | size_t strlcpy(char *dest, const char *src, size_t size) |
27 | { | 27 | { |
28 | size_t ret = strlen(src); | 28 | size_t ret = strlen(src); |
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 316dbe7f86ed..5a4f2b6f3738 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_REGS_H | 1 | #ifndef __PERF_REGS_H |
2 | #define __PERF_REGS_H | 2 | #define __PERF_REGS_H |
3 | 3 | ||
4 | #ifndef NO_PERF_REGS | 4 | #ifdef HAVE_PERF_REGS |
5 | #include <perf_regs.h> | 5 | #include <perf_regs.h> |
6 | #else | 6 | #else |
7 | #define PERF_REGS_MASK 0 | 7 | #define PERF_REGS_MASK 0 |
@@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused) | |||
10 | { | 10 | { |
11 | return NULL; | 11 | return NULL; |
12 | } | 12 | } |
13 | #endif /* NO_PERF_REGS */ | 13 | #endif /* HAVE_PERF_REGS */ |
14 | #endif /* __PERF_REGS_H */ | 14 | #endif /* __PERF_REGS_H */ |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 53c7794fc4be..39f3abac7744 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define __PMU_H | 2 | #define __PMU_H |
3 | 3 | ||
4 | #include <linux/bitops.h> | 4 | #include <linux/bitops.h> |
5 | #include "../../../include/linux/perf_event.h" | 5 | #include "../../../include/uapi/linux/perf_event.h" |
6 | 6 | ||
7 | enum { | 7 | enum { |
8 | PERF_PMU_FORMAT_VALUE_CONFIG, | 8 | PERF_PMU_FORMAT_VALUE_CONFIG, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index aab414fbb64b..dd6426163ba6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include "symbol.h" | 7 | #include "symbol.h" |
8 | #include "thread.h" | 8 | #include "thread.h" |
9 | #include <linux/rbtree.h> | 9 | #include <linux/rbtree.h> |
10 | #include "../../../include/linux/perf_event.h" | 10 | #include "../../../include/uapi/linux/perf_event.h" |
11 | 11 | ||
12 | struct sample_queue; | 12 | struct sample_queue; |
13 | struct ip_callchain; | 13 | struct ip_callchain; |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index d0f9f29cf181..73d510269784 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -23,6 +23,7 @@ cflags += getenv('CFLAGS', '').split() | |||
23 | 23 | ||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | libtraceevent = getenv('LIBTRACEEVENT') | ||
26 | 27 | ||
27 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 28 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
28 | if len(f.strip()) > 0 and f[0] != '#'] | 29 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -31,6 +32,7 @@ perf = Extension('perf', | |||
31 | sources = ext_sources, | 32 | sources = ext_sources, |
32 | include_dirs = ['util/include'], | 33 | include_dirs = ['util/include'], |
33 | extra_compile_args = cflags, | 34 | extra_compile_args = cflags, |
35 | extra_objects = [libtraceevent], | ||
34 | ) | 36 | ) |
35 | 37 | ||
36 | setup(name='perf', | 38 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b5b1b9211960..cfd1c0feb32d 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -260,6 +260,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
260 | if (path != NULL) | 260 | if (path != NULL) |
261 | goto out_path; | 261 | goto out_path; |
262 | 262 | ||
263 | if (!self->ms.map) | ||
264 | goto out_ip; | ||
265 | |||
266 | if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10)) | ||
267 | goto out_ip; | ||
268 | |||
263 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, | 269 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, |
264 | self->ms.map->dso->long_name, self->ip); | 270 | self->ms.map->dso->long_name, self->ip); |
265 | fp = popen(cmd, "r"); | 271 | fp = popen(cmd, "r"); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 12d634792de5..5786f323b597 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from; | |||
43 | extern struct sort_entry sort_sym_to; | 43 | extern struct sort_entry sort_sym_to; |
44 | extern enum sort_type sort__first_dimension; | 44 | extern enum sort_type sort__first_dimension; |
45 | 45 | ||
46 | struct he_stat { | ||
47 | u64 period; | ||
48 | u64 period_sys; | ||
49 | u64 period_us; | ||
50 | u64 period_guest_sys; | ||
51 | u64 period_guest_us; | ||
52 | u32 nr_events; | ||
53 | }; | ||
54 | |||
46 | /** | 55 | /** |
47 | * struct hist_entry - histogram entry | 56 | * struct hist_entry - histogram entry |
48 | * | 57 | * |
@@ -52,16 +61,11 @@ extern enum sort_type sort__first_dimension; | |||
52 | struct hist_entry { | 61 | struct hist_entry { |
53 | struct rb_node rb_node_in; | 62 | struct rb_node rb_node_in; |
54 | struct rb_node rb_node; | 63 | struct rb_node rb_node; |
55 | u64 period; | 64 | struct he_stat stat; |
56 | u64 period_sys; | ||
57 | u64 period_us; | ||
58 | u64 period_guest_sys; | ||
59 | u64 period_guest_us; | ||
60 | struct map_symbol ms; | 65 | struct map_symbol ms; |
61 | struct thread *thread; | 66 | struct thread *thread; |
62 | u64 ip; | 67 | u64 ip; |
63 | s32 cpu; | 68 | s32 cpu; |
64 | u32 nr_events; | ||
65 | 69 | ||
66 | /* XXX These two should move to some tree widget lib */ | 70 | /* XXX These two should move to some tree widget lib */ |
67 | u16 row_offset; | 71 | u16 row_offset; |
@@ -73,12 +77,13 @@ struct hist_entry { | |||
73 | u8 filtered; | 77 | u8 filtered; |
74 | char *srcline; | 78 | char *srcline; |
75 | struct symbol *parent; | 79 | struct symbol *parent; |
80 | unsigned long position; | ||
76 | union { | 81 | union { |
77 | unsigned long position; | ||
78 | struct hist_entry *pair; | 82 | struct hist_entry *pair; |
79 | struct rb_root sorted_chain; | 83 | struct rb_root sorted_chain; |
80 | }; | 84 | }; |
81 | struct branch_info *branch_info; | 85 | struct branch_info *branch_info; |
86 | struct hists *hists; | ||
82 | struct callchain_root callchain[0]; | 87 | struct callchain_root callchain[0]; |
83 | }; | 88 | }; |
84 | 89 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b441b07172b7..8b6ef7fac745 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <byteswap.h> | 12 | #include <byteswap.h> |
13 | #include <libgen.h> | 13 | #include <libgen.h> |
14 | 14 | ||
15 | #ifndef NO_LIBELF_SUPPORT | 15 | #ifdef LIBELF_SUPPORT |
16 | #include <libelf.h> | 16 | #include <libelf.h> |
17 | #include <gelf.h> | 17 | #include <gelf.h> |
18 | #include <elf.h> | 18 | #include <elf.h> |
@@ -46,10 +46,10 @@ char *strxfrchar(char *s, char from, char to); | |||
46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; | 46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; |
47 | * for newer versions we can use mmap to reduce memory usage: | 47 | * for newer versions we can use mmap to reduce memory usage: |
48 | */ | 48 | */ |
49 | #ifdef LIBELF_NO_MMAP | 49 | #ifdef LIBELF_MMAP |
50 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | ||
51 | #else | ||
52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP | 50 | # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP |
51 | #else | ||
52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | ||
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | #ifndef DMGL_PARAMS | 55 | #ifndef DMGL_PARAMS |
@@ -233,7 +233,7 @@ struct symsrc { | |||
233 | int fd; | 233 | int fd; |
234 | enum dso_binary_type type; | 234 | enum dso_binary_type type; |
235 | 235 | ||
236 | #ifndef NO_LIBELF_SUPPORT | 236 | #ifdef LIBELF_SUPPORT |
237 | Elf *elf; | 237 | Elf *elf; |
238 | GElf_Ehdr ehdr; | 238 | GElf_Ehdr ehdr; |
239 | 239 | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index fb4b7ea6752f..8b3e5939afb6 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -39,7 +39,6 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
39 | err = self->comm == NULL ? -ENOMEM : 0; | 39 | err = self->comm == NULL ? -ENOMEM : 0; |
40 | if (!err) { | 40 | if (!err) { |
41 | self->comm_set = true; | 41 | self->comm_set = true; |
42 | map_groups__flush(&self->mg); | ||
43 | } | 42 | } |
44 | return err; | 43 | return err; |
45 | } | 44 | } |
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index a78c8b303bb5..cb6bc503a792 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h | |||
@@ -13,7 +13,7 @@ struct unwind_entry { | |||
13 | 13 | ||
14 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); | 14 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); |
15 | 15 | ||
16 | #ifndef NO_LIBUNWIND_SUPPORT | 16 | #ifdef LIBUNWIND_SUPPORT |
17 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | 17 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, |
18 | struct machine *machine, | 18 | struct machine *machine, |
19 | struct thread *thread, | 19 | struct thread *thread, |
@@ -31,5 +31,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, | |||
31 | { | 31 | { |
32 | return 0; | 32 | return 0; |
33 | } | 33 | } |
34 | #endif /* NO_LIBUNWIND_SUPPORT */ | 34 | #endif /* LIBUNWIND_SUPPORT */ |
35 | #endif /* __UNWIND_H */ | 35 | #endif /* __UNWIND_H */ |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 2055cf38041c..99664598bc1a 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -1,7 +1,7 @@ | |||
1 | #include "../perf.h" | 1 | #include "../perf.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include <sys/mman.h> | 3 | #include <sys/mman.h> |
4 | #ifndef NO_BACKTRACE | 4 | #ifdef BACKTRACE_SUPPORT |
5 | #include <execinfo.h> | 5 | #include <execinfo.h> |
6 | #endif | 6 | #endif |
7 | #include <stdio.h> | 7 | #include <stdio.h> |
@@ -165,7 +165,7 @@ size_t hex_width(u64 v) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | /* Obtain a backtrace and print it to stdout. */ | 167 | /* Obtain a backtrace and print it to stdout. */ |
168 | #ifndef NO_BACKTRACE | 168 | #ifdef BACKTRACE_SUPPORT |
169 | void dump_stack(void) | 169 | void dump_stack(void) |
170 | { | 170 | { |
171 | void *array[16]; | 171 | void *array[16]; |
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile new file mode 100644 index 000000000000..6b9cf7a987c7 --- /dev/null +++ b/tools/power/acpi/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | PROG= acpidump | ||
2 | SRCS= acpidump.c | ||
3 | KERNEL_INCLUDE := ../../../include | ||
4 | CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) | ||
5 | |||
6 | all: acpidump | ||
7 | $(PROG) : $(SRCS) | ||
8 | $(CC) $(CFLAGS) $(SRCS) -o $(PROG) | ||
9 | |||
10 | CLEANFILES= $(PROG) | ||
11 | |||
12 | clean : | ||
13 | rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ | ||
14 | |||
15 | install : | ||
16 | install acpidump /usr/bin/acpidump | ||
17 | install acpidump.8 /usr/share/man/man8 | ||
18 | |||
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/acpidump.8 new file mode 100644 index 000000000000..adfa99166e5e --- /dev/null +++ b/tools/power/acpi/acpidump.8 | |||
@@ -0,0 +1,59 @@ | |||
1 | .TH ACPIDUMP 8 | ||
2 | .SH NAME | ||
3 | acpidump \- Dump system's ACPI tables to an ASCII file. | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B acpidump > acpidump.out | ||
7 | .SH DESCRIPTION | ||
8 | \fBacpidump \fP dumps the systems ACPI tables to an ASCII file | ||
9 | appropriate for attaching to a bug report. | ||
10 | |||
11 | Subsequently, they can be processed by utilities in the ACPICA package. | ||
12 | .SS Options | ||
13 | no options worth worrying about. | ||
14 | .PP | ||
15 | .SH EXAMPLE | ||
16 | |||
17 | .nf | ||
18 | # acpidump > acpidump.out | ||
19 | |||
20 | $ acpixtract -a acpidump.out | ||
21 | Acpi table [DSDT] - 15974 bytes written to DSDT.dat | ||
22 | Acpi table [FACS] - 64 bytes written to FACS.dat | ||
23 | Acpi table [FACP] - 116 bytes written to FACP.dat | ||
24 | Acpi table [APIC] - 120 bytes written to APIC.dat | ||
25 | Acpi table [MCFG] - 60 bytes written to MCFG.dat | ||
26 | Acpi table [SSDT] - 444 bytes written to SSDT1.dat | ||
27 | Acpi table [SSDT] - 439 bytes written to SSDT2.dat | ||
28 | Acpi table [SSDT] - 439 bytes written to SSDT3.dat | ||
29 | Acpi table [SSDT] - 439 bytes written to SSDT4.dat | ||
30 | Acpi table [SSDT] - 439 bytes written to SSDT5.dat | ||
31 | Acpi table [RSDT] - 76 bytes written to RSDT.dat | ||
32 | Acpi table [RSDP] - 20 bytes written to RSDP.dat | ||
33 | |||
34 | $ iasl -d *.dat | ||
35 | ... | ||
36 | .fi | ||
37 | creates *.dsl, a human readable form which can be edited | ||
38 | and compiled using iasl. | ||
39 | |||
40 | |||
41 | .SH NOTES | ||
42 | |||
43 | .B "acpidump " | ||
44 | must be run as root. | ||
45 | |||
46 | .SH REFERENCES | ||
47 | ACPICA: https://acpica.org/ | ||
48 | |||
49 | .SH FILES | ||
50 | .ta | ||
51 | .nf | ||
52 | /dev/mem | ||
53 | /sys/firmware/acpi/tables/dynamic/* | ||
54 | .fi | ||
55 | |||
56 | .PP | ||
57 | .SH AUTHOR | ||
58 | .nf | ||
59 | Written by Len Brown <len.brown@intel.com> | ||
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c new file mode 100644 index 000000000000..a84553a0e0df --- /dev/null +++ b/tools/power/acpi/acpidump.c | |||
@@ -0,0 +1,559 @@ | |||
1 | /* | ||
2 | * (c) Alexey Starikovskiy, Intel, 2005-2006. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions, and the following disclaimer, | ||
10 | * without modification. | ||
11 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
12 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
13 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
14 | * including a substantially similar Disclaimer requirement for further | ||
15 | * binary redistribution. | ||
16 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
17 | * of any contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * NO WARRANTY | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
29 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
33 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
34 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
35 | * POSSIBILITY OF SUCH DAMAGES. | ||
36 | */ | ||
37 | |||
38 | #ifdef DEFINE_ALTERNATE_TYPES | ||
39 | /* hack to enable building old application with new headers -lenb */ | ||
40 | #define acpi_fadt_descriptor acpi_table_fadt | ||
41 | #define acpi_rsdp_descriptor acpi_table_rsdp | ||
42 | #define DSDT_SIG ACPI_SIG_DSDT | ||
43 | #define FACS_SIG ACPI_SIG_FACS | ||
44 | #define FADT_SIG ACPI_SIG_FADT | ||
45 | #define xfirmware_ctrl Xfacs | ||
46 | #define firmware_ctrl facs | ||
47 | |||
48 | typedef int s32; | ||
49 | typedef unsigned char u8; | ||
50 | typedef unsigned short u16; | ||
51 | typedef unsigned int u32; | ||
52 | typedef unsigned long long u64; | ||
53 | typedef long long s64; | ||
54 | #endif | ||
55 | |||
56 | #include <sys/mman.h> | ||
57 | #include <sys/types.h> | ||
58 | #include <sys/stat.h> | ||
59 | #include <fcntl.h> | ||
60 | #include <stdio.h> | ||
61 | #include <string.h> | ||
62 | #include <unistd.h> | ||
63 | #include <getopt.h> | ||
64 | |||
65 | #include <dirent.h> | ||
66 | |||
67 | #include <acpi/acconfig.h> | ||
68 | #include <acpi/platform/acenv.h> | ||
69 | #include <acpi/actypes.h> | ||
70 | #include <acpi/actbl.h> | ||
71 | |||
72 | static inline u8 checksum(u8 * buffer, u32 length) | ||
73 | { | ||
74 | u8 sum = 0, *i = buffer; | ||
75 | buffer += length; | ||
76 | for (; i < buffer; sum += *(i++)); | ||
77 | return sum; | ||
78 | } | ||
79 | |||
80 | static unsigned long psz, addr, length; | ||
81 | static int print, connect, skip; | ||
82 | static u8 select_sig[4]; | ||
83 | |||
84 | static unsigned long read_efi_systab( void ) | ||
85 | { | ||
86 | char buffer[80]; | ||
87 | unsigned long addr; | ||
88 | FILE *f = fopen("/sys/firmware/efi/systab", "r"); | ||
89 | if (f) { | ||
90 | while (fgets(buffer, 80, f)) { | ||
91 | if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1) | ||
92 | return addr; | ||
93 | } | ||
94 | fclose(f); | ||
95 | } | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static u8 *acpi_map_memory(unsigned long where, unsigned length) | ||
100 | { | ||
101 | unsigned long offset; | ||
102 | u8 *there; | ||
103 | int fd = open("/dev/mem", O_RDONLY); | ||
104 | if (fd < 0) { | ||
105 | fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n"); | ||
106 | exit(1); | ||
107 | } | ||
108 | offset = where % psz; | ||
109 | there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE, | ||
110 | fd, where - offset); | ||
111 | close(fd); | ||
112 | if (there == MAP_FAILED) return 0; | ||
113 | return (there + offset); | ||
114 | } | ||
115 | |||
116 | static void acpi_unmap_memory(u8 * there, unsigned length) | ||
117 | { | ||
118 | unsigned long offset = (unsigned long)there % psz; | ||
119 | munmap(there - offset, length + offset); | ||
120 | } | ||
121 | |||
122 | static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig) | ||
123 | { | ||
124 | unsigned size; | ||
125 | struct acpi_table_header *tbl = (struct acpi_table_header *) | ||
126 | acpi_map_memory(where, sizeof(struct acpi_table_header)); | ||
127 | if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0; | ||
128 | size = tbl->length; | ||
129 | acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header)); | ||
130 | return (struct acpi_table_header *)acpi_map_memory(where, size); | ||
131 | } | ||
132 | |||
133 | static void acpi_unmap_table(struct acpi_table_header *tbl) | ||
134 | { | ||
135 | acpi_unmap_memory((u8 *)tbl, tbl->length); | ||
136 | } | ||
137 | |||
138 | static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length) | ||
139 | { | ||
140 | struct acpi_rsdp_descriptor *rsdp; | ||
141 | u8 *i, *end = begin + length; | ||
142 | /* Search from given start address for the requested length */ | ||
143 | for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) { | ||
144 | /* The signature and checksum must both be correct */ | ||
145 | if (memcmp((char *)i, "RSD PTR ", 8)) continue; | ||
146 | rsdp = (struct acpi_rsdp_descriptor *)i; | ||
147 | /* Signature matches, check the appropriate checksum */ | ||
148 | if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ? | ||
149 | ACPI_RSDP_CHECKSUM_LENGTH : | ||
150 | ACPI_RSDP_XCHECKSUM_LENGTH)) | ||
151 | /* Checksum valid, we have found a valid RSDP */ | ||
152 | return rsdp; | ||
153 | } | ||
154 | /* Searched entire block, no RSDP was found */ | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Output data | ||
160 | */ | ||
161 | static void acpi_show_data(int fd, u8 * data, int size) | ||
162 | { | ||
163 | char buffer[256]; | ||
164 | int len; | ||
165 | int i, remain = size; | ||
166 | while (remain > 0) { | ||
167 | len = snprintf(buffer, 256, " %04x:", size - remain); | ||
168 | for (i = 0; i < 16 && i < remain; i++) { | ||
169 | len += | ||
170 | snprintf(&buffer[len], 256 - len, " %02x", data[i]); | ||
171 | } | ||
172 | for (; i < 16; i++) { | ||
173 | len += snprintf(&buffer[len], 256 - len, " "); | ||
174 | } | ||
175 | len += snprintf(&buffer[len], 256 - len, " "); | ||
176 | for (i = 0; i < 16 && i < remain; i++) { | ||
177 | buffer[len++] = (isprint(data[i])) ? data[i] : '.'; | ||
178 | } | ||
179 | buffer[len++] = '\n'; | ||
180 | write(fd, buffer, len); | ||
181 | data += 16; | ||
182 | remain -= 16; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Output ACPI table | ||
188 | */ | ||
189 | static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) | ||
190 | { | ||
191 | char buff[80]; | ||
192 | int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr); | ||
193 | write(fd, buff, len); | ||
194 | acpi_show_data(fd, (u8 *) table, table->length); | ||
195 | buff[0] = '\n'; | ||
196 | write(fd, buff, 1); | ||
197 | } | ||
198 | |||
199 | static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) | ||
200 | { | ||
201 | static int select_done = 0; | ||
202 | if (!select_sig[0]) { | ||
203 | if (print) { | ||
204 | acpi_show_table(fd, tbl, addr); | ||
205 | } else { | ||
206 | write(fd, tbl, tbl->length); | ||
207 | } | ||
208 | } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) { | ||
209 | if (skip > 0) { | ||
210 | --skip; | ||
211 | return; | ||
212 | } | ||
213 | if (print) { | ||
214 | acpi_show_table(fd, tbl, addr); | ||
215 | } else { | ||
216 | write(fd, tbl, tbl->length); | ||
217 | } | ||
218 | select_done = 1; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { | ||
223 | struct acpi_fadt_descriptor x; | ||
224 | unsigned long addr; | ||
225 | size_t len = sizeof(struct acpi_fadt_descriptor); | ||
226 | if (len > tbl->length) len = tbl->length; | ||
227 | memcpy(&x, tbl, len); | ||
228 | x.header.length = len; | ||
229 | if (checksum((u8 *)tbl, len)) { | ||
230 | fprintf(stderr, "Wrong checksum for FADT!\n"); | ||
231 | } | ||
232 | if (x.header.length >= 148 && x.Xdsdt) { | ||
233 | addr = (unsigned long)x.Xdsdt; | ||
234 | if (connect) { | ||
235 | x.Xdsdt = lseek(fd, 0, SEEK_CUR); | ||
236 | } | ||
237 | } else if (x.header.length >= 44 && x.dsdt) { | ||
238 | addr = (unsigned long)x.dsdt; | ||
239 | if (connect) { | ||
240 | x.dsdt = lseek(fd, 0, SEEK_CUR); | ||
241 | } | ||
242 | } else { | ||
243 | fprintf(stderr, "No DSDT in FADT!\n"); | ||
244 | goto no_dsdt; | ||
245 | } | ||
246 | tbl = acpi_map_table(addr, DSDT_SIG); | ||
247 | if (!tbl) goto no_dsdt; | ||
248 | if (checksum((u8 *)tbl, tbl->length)) | ||
249 | fprintf(stderr, "Wrong checksum for DSDT!\n"); | ||
250 | write_table(fd, tbl, addr); | ||
251 | acpi_unmap_table(tbl); | ||
252 | no_dsdt: | ||
253 | if (x.header.length >= 140 && x.xfirmware_ctrl) { | ||
254 | addr = (unsigned long)x.xfirmware_ctrl; | ||
255 | if (connect) { | ||
256 | x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR); | ||
257 | } | ||
258 | } else if (x.header.length >= 40 && x.firmware_ctrl) { | ||
259 | addr = (unsigned long)x.firmware_ctrl; | ||
260 | if (connect) { | ||
261 | x.firmware_ctrl = lseek(fd, 0, SEEK_CUR); | ||
262 | } | ||
263 | } else { | ||
264 | fprintf(stderr, "No FACS in FADT!\n"); | ||
265 | goto no_facs; | ||
266 | } | ||
267 | tbl = acpi_map_table(addr, FACS_SIG); | ||
268 | if (!tbl) goto no_facs; | ||
269 | /* do not checksum FACS */ | ||
270 | write_table(fd, tbl, addr); | ||
271 | acpi_unmap_table(tbl); | ||
272 | no_facs: | ||
273 | write_table(fd, (struct acpi_table_header *)&x, xaddr); | ||
274 | } | ||
275 | |||
276 | static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp) | ||
277 | { | ||
278 | struct acpi_table_header *sdt, *tbl = 0; | ||
279 | int xsdt = 1, i, num; | ||
280 | char *offset; | ||
281 | unsigned long addr; | ||
282 | if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { | ||
283 | tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); | ||
284 | } | ||
285 | if (!tbl && rsdp->rsdt_physical_address) { | ||
286 | xsdt = 0; | ||
287 | tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); | ||
288 | } | ||
289 | if (!tbl) return 0; | ||
290 | sdt = malloc(tbl->length); | ||
291 | memcpy(sdt, tbl, tbl->length); | ||
292 | acpi_unmap_table(tbl); | ||
293 | if (checksum((u8 *)sdt, sdt->length)) | ||
294 | fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT"); | ||
295 | num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32)); | ||
296 | offset = (char *)sdt + sizeof(struct acpi_table_header); | ||
297 | for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) { | ||
298 | addr = (xsdt) ? (unsigned long)(*(u64 *)offset): | ||
299 | (unsigned long)(*(u32 *)offset); | ||
300 | if (!addr) continue; | ||
301 | tbl = acpi_map_table(addr, 0); | ||
302 | if (!tbl) continue; | ||
303 | if (!memcmp(tbl->signature, FADT_SIG, 4)) { | ||
304 | acpi_dump_FADT(fd, tbl, addr); | ||
305 | } else { | ||
306 | if (checksum((u8 *)tbl, tbl->length)) | ||
307 | fprintf(stderr, "Wrong checksum for generic table!\n"); | ||
308 | write_table(fd, tbl, addr); | ||
309 | } | ||
310 | acpi_unmap_table(tbl); | ||
311 | if (connect) { | ||
312 | if (xsdt) | ||
313 | (*(u64*)offset) = lseek(fd, 0, SEEK_CUR); | ||
314 | else | ||
315 | (*(u32*)offset) = lseek(fd, 0, SEEK_CUR); | ||
316 | } | ||
317 | } | ||
318 | if (xsdt) { | ||
319 | addr = (unsigned long)rsdp->xsdt_physical_address; | ||
320 | if (connect) { | ||
321 | rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
322 | } | ||
323 | } else { | ||
324 | addr = (unsigned long)rsdp->rsdt_physical_address; | ||
325 | if (connect) { | ||
326 | rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); | ||
327 | } | ||
328 | } | ||
329 | write_table(fd, sdt, addr); | ||
330 | free (sdt); | ||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | #define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic" | ||
335 | |||
336 | static void acpi_dump_dynamic_SSDT(int fd) | ||
337 | { | ||
338 | struct stat file_stat; | ||
339 | char filename[256], *ptr; | ||
340 | DIR *tabledir; | ||
341 | struct dirent *entry; | ||
342 | FILE *fp; | ||
343 | int count, readcount, length; | ||
344 | struct acpi_table_header table_header, *ptable; | ||
345 | |||
346 | if (stat(DYNAMIC_SSDT, &file_stat) == -1) { | ||
347 | /* The directory doesn't exist */ | ||
348 | return; | ||
349 | } | ||
350 | tabledir = opendir(DYNAMIC_SSDT); | ||
351 | if(!tabledir){ | ||
352 | /*can't open the directory */ | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | while ((entry = readdir(tabledir)) != 0){ | ||
357 | /* skip the file of . /.. */ | ||
358 | if (entry->d_name[0] == '.') | ||
359 | continue; | ||
360 | |||
361 | sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name); | ||
362 | fp = fopen(filename, "r"); | ||
363 | if (fp == NULL) { | ||
364 | fprintf(stderr, "Can't open the file of %s\n", | ||
365 | filename); | ||
366 | continue; | ||
367 | } | ||
368 | /* Read the Table header to parse the table length */ | ||
369 | count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); | ||
370 | if (count < sizeof(table_header)) { | ||
371 | /* the length is lessn than ACPI table header. skip it */ | ||
372 | fclose(fp); | ||
373 | continue; | ||
374 | } | ||
375 | length = table_header.length; | ||
376 | ptr = malloc(table_header.length); | ||
377 | fseek(fp, 0, SEEK_SET); | ||
378 | readcount = 0; | ||
379 | while(!feof(fp) && readcount < length) { | ||
380 | count = fread(ptr + readcount, 1, 256, fp); | ||
381 | readcount += count; | ||
382 | } | ||
383 | fclose(fp); | ||
384 | ptable = (struct acpi_table_header *) ptr; | ||
385 | if (checksum((u8 *) ptable, ptable->length)) | ||
386 | fprintf(stderr, "Wrong checksum " | ||
387 | "for dynamic SSDT table!\n"); | ||
388 | write_table(fd, ptable, 0); | ||
389 | free(ptr); | ||
390 | } | ||
391 | closedir(tabledir); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | static void usage(const char *progname) | ||
396 | { | ||
397 | puts("Usage:"); | ||
398 | printf("%s [--addr 0x1234][--table DSDT][--output filename]" | ||
399 | "[--binary][--length 0x456][--help]\n", progname); | ||
400 | puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address"); | ||
401 | puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature"); | ||
402 | puts("\t--output filename or -o filename -- redirect output from stdin to filename"); | ||
403 | puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format"); | ||
404 | puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory" | ||
405 | "\n\t\tregion without trying to understand it's contents"); | ||
406 | puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one"); | ||
407 | puts("\t--help or -h -- this help message"); | ||
408 | exit(0); | ||
409 | } | ||
410 | |||
411 | static struct option long_options[] = { | ||
412 | {"addr", 1, 0, 0}, | ||
413 | {"table", 1, 0, 0}, | ||
414 | {"output", 1, 0, 0}, | ||
415 | {"binary", 0, 0, 0}, | ||
416 | {"length", 1, 0, 0}, | ||
417 | {"skip", 1, 0, 0}, | ||
418 | {"help", 0, 0, 0}, | ||
419 | {0, 0, 0, 0} | ||
420 | }; | ||
421 | int main(int argc, char **argv) | ||
422 | { | ||
423 | int option_index, c, fd; | ||
424 | u8 *raw; | ||
425 | struct acpi_rsdp_descriptor rsdpx, *x = 0; | ||
426 | char *filename = 0; | ||
427 | char buff[80]; | ||
428 | memset(select_sig, 0, 4); | ||
429 | print = 1; | ||
430 | connect = 0; | ||
431 | addr = length = 0; | ||
432 | skip = 0; | ||
433 | while (1) { | ||
434 | option_index = 0; | ||
435 | c = getopt_long(argc, argv, "a:t:o:bl:s:h", | ||
436 | long_options, &option_index); | ||
437 | if (c == -1) | ||
438 | break; | ||
439 | |||
440 | switch (c) { | ||
441 | case 0: | ||
442 | switch (option_index) { | ||
443 | case 0: | ||
444 | addr = strtoul(optarg, (char **)NULL, 16); | ||
445 | break; | ||
446 | case 1: | ||
447 | memcpy(select_sig, optarg, 4); | ||
448 | break; | ||
449 | case 2: | ||
450 | filename = optarg; | ||
451 | break; | ||
452 | case 3: | ||
453 | print = 0; | ||
454 | break; | ||
455 | case 4: | ||
456 | length = strtoul(optarg, (char **)NULL, 16); | ||
457 | break; | ||
458 | case 5: | ||
459 | skip = strtoul(optarg, (char **)NULL, 10); | ||
460 | break; | ||
461 | case 6: | ||
462 | usage(argv[0]); | ||
463 | exit(0); | ||
464 | } | ||
465 | break; | ||
466 | case 'a': | ||
467 | addr = strtoul(optarg, (char **)NULL, 16); | ||
468 | break; | ||
469 | case 't': | ||
470 | memcpy(select_sig, optarg, 4); | ||
471 | break; | ||
472 | case 'o': | ||
473 | filename = optarg; | ||
474 | break; | ||
475 | case 'b': | ||
476 | print = 0; | ||
477 | break; | ||
478 | case 'l': | ||
479 | length = strtoul(optarg, (char **)NULL, 16); | ||
480 | break; | ||
481 | case 's': | ||
482 | skip = strtoul(optarg, (char **)NULL, 10); | ||
483 | break; | ||
484 | case 'h': | ||
485 | usage(argv[0]); | ||
486 | exit(0); | ||
487 | default: | ||
488 | printf("Unknown option!\n"); | ||
489 | usage(argv[0]); | ||
490 | exit(0); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | fd = STDOUT_FILENO; | ||
495 | if (filename) { | ||
496 | fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); | ||
497 | if (fd < 0) | ||
498 | return fd; | ||
499 | } | ||
500 | |||
501 | if (!select_sig[0] && !print) { | ||
502 | connect = 1; | ||
503 | } | ||
504 | |||
505 | psz = sysconf(_SC_PAGESIZE); | ||
506 | if (length && addr) { | ||
507 | /* We know length and address, it means we just want a memory dump */ | ||
508 | if (!(raw = acpi_map_memory(addr, length))) | ||
509 | goto not_found; | ||
510 | write(fd, raw, length); | ||
511 | acpi_unmap_memory(raw, length); | ||
512 | close(fd); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | length = sizeof(struct acpi_rsdp_descriptor); | ||
517 | if (!addr) { | ||
518 | addr = read_efi_systab(); | ||
519 | if (!addr) { | ||
520 | addr = ACPI_HI_RSDP_WINDOW_BASE; | ||
521 | length = ACPI_HI_RSDP_WINDOW_SIZE; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | if (!(raw = acpi_map_memory(addr, length)) || | ||
526 | !(x = acpi_scan_for_rsdp(raw, length))) | ||
527 | goto not_found; | ||
528 | |||
529 | /* Find RSDP and print all found tables */ | ||
530 | memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor)); | ||
531 | acpi_unmap_memory(raw, length); | ||
532 | if (connect) { | ||
533 | lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); | ||
534 | } | ||
535 | if (!acpi_dump_SDT(fd, &rsdpx)) | ||
536 | goto not_found; | ||
537 | if (connect) { | ||
538 | lseek(fd, 0, SEEK_SET); | ||
539 | write(fd, x, (rsdpx.revision < 2) ? | ||
540 | ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); | ||
541 | } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) { | ||
542 | addr += (long)x - (long)raw; | ||
543 | length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr); | ||
544 | write(fd, buff, length); | ||
545 | acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ? | ||
546 | ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); | ||
547 | buff[0] = '\n'; | ||
548 | write(fd, buff, 1); | ||
549 | } | ||
550 | acpi_dump_dynamic_SSDT(fd); | ||
551 | close(fd); | ||
552 | return 0; | ||
553 | not_found: | ||
554 | close(fd); | ||
555 | fprintf(stderr, "ACPI tables were not found. If you know location " | ||
556 | "of RSD PTR table (from dmesg, etc), " | ||
557 | "supply it with either --addr or -a option\n"); | ||
558 | return 1; | ||
559 | } | ||
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index a93e06cfcc2a..cf397bd26d0c 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -111,7 +111,7 @@ GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; | |||
111 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | 111 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS |
112 | 112 | ||
113 | # check if compiler option is supported | 113 | # check if compiler option is supported |
114 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | 114 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} |
115 | 115 | ||
116 | # use '-Os' optimization if available, else use -O2 | 116 | # use '-Os' optimization if available, else use -O2 |
117 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | 117 | OPTIMIZATION := $(call cc-supports,-Os,-O2) |
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 74e44507dfe9..e4d0690cccf9 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 | |||
@@ -4,15 +4,11 @@ turbostat \- Report processor frequency and idle statistics | |||
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .ft B | 5 | .ft B |
6 | .B turbostat | 6 | .B turbostat |
7 | .RB [ "\-s" ] | 7 | .RB [ Options ] |
8 | .RB [ "\-v" ] | ||
9 | .RB [ "\-M MSR#" ] | ||
10 | .RB command | 8 | .RB command |
11 | .br | 9 | .br |
12 | .B turbostat | 10 | .B turbostat |
13 | .RB [ "\-s" ] | 11 | .RB [ Options ] |
14 | .RB [ "\-v" ] | ||
15 | .RB [ "\-M MSR#" ] | ||
16 | .RB [ "\-i interval_sec" ] | 12 | .RB [ "\-i interval_sec" ] |
17 | .SH DESCRIPTION | 13 | .SH DESCRIPTION |
18 | \fBturbostat \fP reports processor topology, frequency | 14 | \fBturbostat \fP reports processor topology, frequency |
@@ -27,16 +23,23 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs. | |||
27 | on processors that additionally support C-state residency counters. | 23 | on processors that additionally support C-state residency counters. |
28 | 24 | ||
29 | .SS Options | 25 | .SS Options |
30 | The \fB-s\fP option limits output to a 1-line system summary for each interval. | 26 | The \fB-p\fP option limits output to the 1st thread in 1st core of each package. |
31 | .PP | 27 | .PP |
32 | The \fB-c\fP option limits output to the 1st thread in each core. | 28 | The \fB-P\fP option limits output to the 1st thread in each Package. |
33 | .PP | 29 | .PP |
34 | The \fB-p\fP option limits output to the 1st thread in each package. | 30 | The \fB-S\fP option limits output to a 1-line System Summary for each interval. |
35 | .PP | 31 | .PP |
36 | The \fB-v\fP option increases verbosity. | 32 | The \fB-v\fP option increases verbosity. |
37 | .PP | 33 | .PP |
38 | The \fB-M MSR#\fP option dumps the specified MSR, | 34 | The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34" |
39 | in addition to the usual frequency and idle statistics. | 35 | .PP |
36 | The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter. | ||
37 | .PP | ||
38 | The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter. | ||
39 | .PP | ||
40 | The \fB-m MSR#\fP option includes the the specified 32-bit MSR value. | ||
41 | .PP | ||
42 | The \fB-M MSR#\fP option includes the the specified 64-bit MSR value. | ||
40 | .PP | 43 | .PP |
41 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. | 44 | The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. |
42 | The default is 5 seconds. | 45 | The default is 5 seconds. |
@@ -150,6 +153,29 @@ Note that turbostat reports average GHz of 3.63, while | |||
150 | the arithmetic average of the GHz column above is lower. | 153 | the arithmetic average of the GHz column above is lower. |
151 | This is a weighted average, where the weight is %c0. ie. it is the total number of | 154 | This is a weighted average, where the weight is %c0. ie. it is the total number of |
152 | un-halted cycles elapsed per time divided by the number of CPUs. | 155 | un-halted cycles elapsed per time divided by the number of CPUs. |
156 | .SH SMI COUNTING EXAMPLE | ||
157 | On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. | ||
158 | Using the -m option, you can display how many SMIs have fired since reset, or if there | ||
159 | are SMIs during the measurement interval, you can display the delta using the -d option. | ||
160 | .nf | ||
161 | [root@x980 ~]# turbostat -m 0x34 | ||
162 | cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6 | ||
163 | 1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55 | ||
164 | 0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55 | ||
165 | 0 6 0.14 1.63 3.38 0x00000056 5.30 | ||
166 | 1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52 | ||
167 | 1 8 0.10 1.65 3.38 0x00000056 18.05 | ||
168 | 2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50 | ||
169 | 2 10 0.10 1.63 3.38 0x00000056 6.93 | ||
170 | 8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16 | ||
171 | 8 7 0.08 1.64 3.38 0x00000056 5.12 | ||
172 | 9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38 | ||
173 | 9 9 0.09 1.68 3.38 0x00000056 9.32 | ||
174 | 10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23 | ||
175 | 10 11 1.72 1.65 3.38 0x00000056 15.05 | ||
176 | ^C | ||
177 | [root@x980 ~]# | ||
178 | .fi | ||
153 | .SH NOTES | 179 | .SH NOTES |
154 | 180 | ||
155 | .B "turbostat " | 181 | .B "turbostat " |
@@ -165,6 +191,13 @@ may work poorly on Linux-2.6.20 through 2.6.29, | |||
165 | as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF | 191 | as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF |
166 | in those kernels. | 192 | in those kernels. |
167 | 193 | ||
194 | If the TSC column does not make sense, then | ||
195 | the other numbers will also make no sense. | ||
196 | Turbostat is lightweight, and its data collection is not atomic. | ||
197 | These issues are usually caused by an extremely short measurement | ||
198 | interval (much less than 1 second), or system activity that prevents | ||
199 | turbostat from being able to run on all CPUS to quickly collect data. | ||
200 | |||
168 | The APERF, MPERF MSRs are defined to count non-halted cycles. | 201 | The APERF, MPERF MSRs are defined to count non-halted cycles. |
169 | Although it is not guaranteed by the architecture, turbostat assumes | 202 | Although it is not guaranteed by the architecture, turbostat assumes |
170 | that they count at TSC rate, which is true on all processors tested to date. | 203 | that they count at TSC rate, which is true on all processors tested to date. |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 861d77190206..2655ae9a3ad8 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -35,9 +35,9 @@ | |||
35 | #include <ctype.h> | 35 | #include <ctype.h> |
36 | #include <sched.h> | 36 | #include <sched.h> |
37 | 37 | ||
38 | #define MSR_TSC 0x10 | ||
39 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE | 38 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE |
40 | #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD | 39 | #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD |
40 | #define MSR_IVT_TURBO_RATIO_LIMIT 0x1AE | ||
41 | #define MSR_APERF 0xE8 | 41 | #define MSR_APERF 0xE8 |
42 | #define MSR_MPERF 0xE7 | 42 | #define MSR_MPERF 0xE7 |
43 | #define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ | 43 | #define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ |
@@ -62,7 +62,11 @@ unsigned int genuine_intel; | |||
62 | unsigned int has_invariant_tsc; | 62 | unsigned int has_invariant_tsc; |
63 | unsigned int do_nehalem_platform_info; | 63 | unsigned int do_nehalem_platform_info; |
64 | unsigned int do_nehalem_turbo_ratio_limit; | 64 | unsigned int do_nehalem_turbo_ratio_limit; |
65 | unsigned int extra_msr_offset; | 65 | unsigned int do_ivt_turbo_ratio_limit; |
66 | unsigned int extra_msr_offset32; | ||
67 | unsigned int extra_msr_offset64; | ||
68 | unsigned int extra_delta_offset32; | ||
69 | unsigned int extra_delta_offset64; | ||
66 | double bclk; | 70 | double bclk; |
67 | unsigned int show_pkg; | 71 | unsigned int show_pkg; |
68 | unsigned int show_core; | 72 | unsigned int show_core; |
@@ -83,7 +87,10 @@ struct thread_data { | |||
83 | unsigned long long aperf; | 87 | unsigned long long aperf; |
84 | unsigned long long mperf; | 88 | unsigned long long mperf; |
85 | unsigned long long c1; /* derived */ | 89 | unsigned long long c1; /* derived */ |
86 | unsigned long long extra_msr; | 90 | unsigned long long extra_msr64; |
91 | unsigned long long extra_delta64; | ||
92 | unsigned long long extra_msr32; | ||
93 | unsigned long long extra_delta32; | ||
87 | unsigned int cpu_id; | 94 | unsigned int cpu_id; |
88 | unsigned int flags; | 95 | unsigned int flags; |
89 | #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 | 96 | #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 |
@@ -222,6 +229,14 @@ void print_header(void) | |||
222 | if (has_aperf) | 229 | if (has_aperf) |
223 | outp += sprintf(outp, " GHz"); | 230 | outp += sprintf(outp, " GHz"); |
224 | outp += sprintf(outp, " TSC"); | 231 | outp += sprintf(outp, " TSC"); |
232 | if (extra_delta_offset32) | ||
233 | outp += sprintf(outp, " count 0x%03X", extra_delta_offset32); | ||
234 | if (extra_delta_offset64) | ||
235 | outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64); | ||
236 | if (extra_msr_offset32) | ||
237 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32); | ||
238 | if (extra_msr_offset64) | ||
239 | outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64); | ||
225 | if (do_nhm_cstates) | 240 | if (do_nhm_cstates) |
226 | outp += sprintf(outp, " %%c1"); | 241 | outp += sprintf(outp, " %%c1"); |
227 | if (do_nhm_cstates) | 242 | if (do_nhm_cstates) |
@@ -238,8 +253,6 @@ void print_header(void) | |||
238 | outp += sprintf(outp, " %%pc6"); | 253 | outp += sprintf(outp, " %%pc6"); |
239 | if (do_snb_cstates) | 254 | if (do_snb_cstates) |
240 | outp += sprintf(outp, " %%pc7"); | 255 | outp += sprintf(outp, " %%pc7"); |
241 | if (extra_msr_offset) | ||
242 | outp += sprintf(outp, " MSR 0x%x ", extra_msr_offset); | ||
243 | 256 | ||
244 | outp += sprintf(outp, "\n"); | 257 | outp += sprintf(outp, "\n"); |
245 | } | 258 | } |
@@ -255,8 +268,14 @@ int dump_counters(struct thread_data *t, struct core_data *c, | |||
255 | fprintf(stderr, "aperf: %016llX\n", t->aperf); | 268 | fprintf(stderr, "aperf: %016llX\n", t->aperf); |
256 | fprintf(stderr, "mperf: %016llX\n", t->mperf); | 269 | fprintf(stderr, "mperf: %016llX\n", t->mperf); |
257 | fprintf(stderr, "c1: %016llX\n", t->c1); | 270 | fprintf(stderr, "c1: %016llX\n", t->c1); |
271 | fprintf(stderr, "msr0x%x: %08llX\n", | ||
272 | extra_delta_offset32, t->extra_delta32); | ||
258 | fprintf(stderr, "msr0x%x: %016llX\n", | 273 | fprintf(stderr, "msr0x%x: %016llX\n", |
259 | extra_msr_offset, t->extra_msr); | 274 | extra_delta_offset64, t->extra_delta64); |
275 | fprintf(stderr, "msr0x%x: %08llX\n", | ||
276 | extra_msr_offset32, t->extra_msr32); | ||
277 | fprintf(stderr, "msr0x%x: %016llX\n", | ||
278 | extra_msr_offset64, t->extra_msr64); | ||
260 | } | 279 | } |
261 | 280 | ||
262 | if (c) { | 281 | if (c) { |
@@ -360,6 +379,21 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
360 | /* TSC */ | 379 | /* TSC */ |
361 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); | 380 | outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); |
362 | 381 | ||
382 | /* delta */ | ||
383 | if (extra_delta_offset32) | ||
384 | outp += sprintf(outp, " %11llu", t->extra_delta32); | ||
385 | |||
386 | /* DELTA */ | ||
387 | if (extra_delta_offset64) | ||
388 | outp += sprintf(outp, " %11llu", t->extra_delta64); | ||
389 | /* msr */ | ||
390 | if (extra_msr_offset32) | ||
391 | outp += sprintf(outp, " 0x%08llx", t->extra_msr32); | ||
392 | |||
393 | /* MSR */ | ||
394 | if (extra_msr_offset64) | ||
395 | outp += sprintf(outp, " 0x%016llx", t->extra_msr64); | ||
396 | |||
363 | if (do_nhm_cstates) { | 397 | if (do_nhm_cstates) { |
364 | if (!skip_c1) | 398 | if (!skip_c1) |
365 | outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); | 399 | outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); |
@@ -391,8 +425,6 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
391 | if (do_snb_cstates) | 425 | if (do_snb_cstates) |
392 | outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); | 426 | outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); |
393 | done: | 427 | done: |
394 | if (extra_msr_offset) | ||
395 | outp += sprintf(outp, " 0x%016llx", t->extra_msr); | ||
396 | outp += sprintf(outp, "\n"); | 428 | outp += sprintf(outp, "\n"); |
397 | 429 | ||
398 | return 0; | 430 | return 0; |
@@ -502,10 +534,16 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
502 | old->mperf = 1; /* divide by 0 protection */ | 534 | old->mperf = 1; /* divide by 0 protection */ |
503 | } | 535 | } |
504 | 536 | ||
537 | old->extra_delta32 = new->extra_delta32 - old->extra_delta32; | ||
538 | old->extra_delta32 &= 0xFFFFFFFF; | ||
539 | |||
540 | old->extra_delta64 = new->extra_delta64 - old->extra_delta64; | ||
541 | |||
505 | /* | 542 | /* |
506 | * for "extra msr", just copy the latest w/o subtracting | 543 | * Extra MSR is just a snapshot, simply copy latest w/o subtracting |
507 | */ | 544 | */ |
508 | old->extra_msr = new->extra_msr; | 545 | old->extra_msr32 = new->extra_msr32; |
546 | old->extra_msr64 = new->extra_msr64; | ||
509 | } | 547 | } |
510 | 548 | ||
511 | int delta_cpu(struct thread_data *t, struct core_data *c, | 549 | int delta_cpu(struct thread_data *t, struct core_data *c, |
@@ -533,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data | |||
533 | t->mperf = 0; | 571 | t->mperf = 0; |
534 | t->c1 = 0; | 572 | t->c1 = 0; |
535 | 573 | ||
574 | t->extra_delta32 = 0; | ||
575 | t->extra_delta64 = 0; | ||
576 | |||
536 | /* tells format_counters to dump all fields from this set */ | 577 | /* 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; | 578 | t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; |
538 | 579 | ||
@@ -553,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c, | |||
553 | average.threads.mperf += t->mperf; | 594 | average.threads.mperf += t->mperf; |
554 | average.threads.c1 += t->c1; | 595 | average.threads.c1 += t->c1; |
555 | 596 | ||
597 | average.threads.extra_delta32 += t->extra_delta32; | ||
598 | average.threads.extra_delta64 += t->extra_delta64; | ||
599 | |||
556 | /* sum per-core values only for 1st thread in core */ | 600 | /* sum per-core values only for 1st thread in core */ |
557 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) | 601 | if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) |
558 | return 0; | 602 | return 0; |
@@ -588,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c, | |||
588 | average.threads.mperf /= topo.num_cpus; | 632 | average.threads.mperf /= topo.num_cpus; |
589 | average.threads.c1 /= topo.num_cpus; | 633 | average.threads.c1 /= topo.num_cpus; |
590 | 634 | ||
635 | average.threads.extra_delta32 /= topo.num_cpus; | ||
636 | average.threads.extra_delta32 &= 0xFFFFFFFF; | ||
637 | |||
638 | average.threads.extra_delta64 /= topo.num_cpus; | ||
639 | |||
591 | average.cores.c3 /= topo.num_cores; | 640 | average.cores.c3 /= topo.num_cores; |
592 | average.cores.c6 /= topo.num_cores; | 641 | average.cores.c6 /= topo.num_cores; |
593 | average.cores.c7 /= topo.num_cores; | 642 | average.cores.c7 /= topo.num_cores; |
@@ -629,8 +678,24 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) | |||
629 | return -4; | 678 | return -4; |
630 | } | 679 | } |
631 | 680 | ||
632 | if (extra_msr_offset) | 681 | if (extra_delta_offset32) { |
633 | if (get_msr(cpu, extra_msr_offset, &t->extra_msr)) | 682 | if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32)) |
683 | return -5; | ||
684 | t->extra_delta32 &= 0xFFFFFFFF; | ||
685 | } | ||
686 | |||
687 | if (extra_delta_offset64) | ||
688 | if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64)) | ||
689 | return -5; | ||
690 | |||
691 | if (extra_msr_offset32) { | ||
692 | if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32)) | ||
693 | return -5; | ||
694 | t->extra_msr32 &= 0xFFFFFFFF; | ||
695 | } | ||
696 | |||
697 | if (extra_msr_offset64) | ||
698 | if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) | ||
634 | return -5; | 699 | return -5; |
635 | 700 | ||
636 | /* collect core counters only for 1st thread in core */ | 701 | /* collect core counters only for 1st thread in core */ |
@@ -677,6 +742,9 @@ void print_verbose_header(void) | |||
677 | 742 | ||
678 | get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); | 743 | get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); |
679 | 744 | ||
745 | if (verbose > 1) | ||
746 | fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); | ||
747 | |||
680 | ratio = (msr >> 40) & 0xFF; | 748 | ratio = (msr >> 40) & 0xFF; |
681 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", | 749 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", |
682 | ratio, bclk, ratio * bclk); | 750 | ratio, bclk, ratio * bclk); |
@@ -685,14 +753,84 @@ void print_verbose_header(void) | |||
685 | fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", | 753 | fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", |
686 | ratio, bclk, ratio * bclk); | 754 | ratio, bclk, ratio * bclk); |
687 | 755 | ||
756 | if (!do_ivt_turbo_ratio_limit) | ||
757 | goto print_nhm_turbo_ratio_limits; | ||
758 | |||
759 | get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr); | ||
760 | |||
688 | if (verbose > 1) | 761 | if (verbose > 1) |
689 | fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); | 762 | fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr); |
763 | |||
764 | ratio = (msr >> 56) & 0xFF; | ||
765 | if (ratio) | ||
766 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n", | ||
767 | ratio, bclk, ratio * bclk); | ||
768 | |||
769 | ratio = (msr >> 48) & 0xFF; | ||
770 | if (ratio) | ||
771 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n", | ||
772 | ratio, bclk, ratio * bclk); | ||
773 | |||
774 | ratio = (msr >> 40) & 0xFF; | ||
775 | if (ratio) | ||
776 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n", | ||
777 | ratio, bclk, ratio * bclk); | ||
778 | |||
779 | ratio = (msr >> 32) & 0xFF; | ||
780 | if (ratio) | ||
781 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n", | ||
782 | ratio, bclk, ratio * bclk); | ||
783 | |||
784 | ratio = (msr >> 24) & 0xFF; | ||
785 | if (ratio) | ||
786 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n", | ||
787 | ratio, bclk, ratio * bclk); | ||
788 | |||
789 | ratio = (msr >> 16) & 0xFF; | ||
790 | if (ratio) | ||
791 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n", | ||
792 | ratio, bclk, ratio * bclk); | ||
793 | |||
794 | ratio = (msr >> 8) & 0xFF; | ||
795 | if (ratio) | ||
796 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n", | ||
797 | ratio, bclk, ratio * bclk); | ||
798 | |||
799 | ratio = (msr >> 0) & 0xFF; | ||
800 | if (ratio) | ||
801 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n", | ||
802 | ratio, bclk, ratio * bclk); | ||
803 | |||
804 | print_nhm_turbo_ratio_limits: | ||
690 | 805 | ||
691 | if (!do_nehalem_turbo_ratio_limit) | 806 | if (!do_nehalem_turbo_ratio_limit) |
692 | return; | 807 | return; |
693 | 808 | ||
694 | get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); | 809 | get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); |
695 | 810 | ||
811 | if (verbose > 1) | ||
812 | fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr); | ||
813 | |||
814 | ratio = (msr >> 56) & 0xFF; | ||
815 | if (ratio) | ||
816 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n", | ||
817 | ratio, bclk, ratio * bclk); | ||
818 | |||
819 | ratio = (msr >> 48) & 0xFF; | ||
820 | if (ratio) | ||
821 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n", | ||
822 | ratio, bclk, ratio * bclk); | ||
823 | |||
824 | ratio = (msr >> 40) & 0xFF; | ||
825 | if (ratio) | ||
826 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n", | ||
827 | ratio, bclk, ratio * bclk); | ||
828 | |||
829 | ratio = (msr >> 32) & 0xFF; | ||
830 | if (ratio) | ||
831 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n", | ||
832 | ratio, bclk, ratio * bclk); | ||
833 | |||
696 | ratio = (msr >> 24) & 0xFF; | 834 | ratio = (msr >> 24) & 0xFF; |
697 | if (ratio) | 835 | if (ratio) |
698 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", | 836 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", |
@@ -712,7 +850,6 @@ void print_verbose_header(void) | |||
712 | if (ratio) | 850 | if (ratio) |
713 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", | 851 | fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", |
714 | ratio, bclk, ratio * bclk); | 852 | ratio, bclk, ratio * bclk); |
715 | |||
716 | } | 853 | } |
717 | 854 | ||
718 | void free_all_buffers(void) | 855 | void free_all_buffers(void) |
@@ -1038,7 +1175,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1038 | case 0x2A: /* SNB */ | 1175 | case 0x2A: /* SNB */ |
1039 | case 0x2D: /* SNB Xeon */ | 1176 | case 0x2D: /* SNB Xeon */ |
1040 | case 0x3A: /* IVB */ | 1177 | case 0x3A: /* IVB */ |
1041 | case 0x3D: /* IVB Xeon */ | 1178 | case 0x3E: /* IVB Xeon */ |
1042 | return 1; | 1179 | return 1; |
1043 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ | 1180 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ |
1044 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ | 1181 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ |
@@ -1046,6 +1183,22 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1046 | return 0; | 1183 | return 0; |
1047 | } | 1184 | } |
1048 | } | 1185 | } |
1186 | int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) | ||
1187 | { | ||
1188 | if (!genuine_intel) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (family != 6) | ||
1192 | return 0; | ||
1193 | |||
1194 | switch (model) { | ||
1195 | case 0x3E: /* IVB Xeon */ | ||
1196 | return 1; | ||
1197 | default: | ||
1198 | return 0; | ||
1199 | } | ||
1200 | } | ||
1201 | |||
1049 | 1202 | ||
1050 | int is_snb(unsigned int family, unsigned int model) | 1203 | int is_snb(unsigned int family, unsigned int model) |
1051 | { | 1204 | { |
@@ -1056,7 +1209,7 @@ int is_snb(unsigned int family, unsigned int model) | |||
1056 | case 0x2A: | 1209 | case 0x2A: |
1057 | case 0x2D: | 1210 | case 0x2D: |
1058 | case 0x3A: /* IVB */ | 1211 | case 0x3A: /* IVB */ |
1059 | case 0x3D: /* IVB Xeon */ | 1212 | case 0x3E: /* IVB Xeon */ |
1060 | return 1; | 1213 | return 1; |
1061 | } | 1214 | } |
1062 | return 0; | 1215 | return 0; |
@@ -1145,12 +1298,13 @@ void check_cpuid() | |||
1145 | bclk = discover_bclk(family, model); | 1298 | bclk = discover_bclk(family, model); |
1146 | 1299 | ||
1147 | do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); | 1300 | do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); |
1301 | do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); | ||
1148 | } | 1302 | } |
1149 | 1303 | ||
1150 | 1304 | ||
1151 | void usage() | 1305 | void usage() |
1152 | { | 1306 | { |
1153 | fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n", | 1307 | fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", |
1154 | progname); | 1308 | progname); |
1155 | exit(1); | 1309 | exit(1); |
1156 | } | 1310 | } |
@@ -1440,15 +1594,15 @@ void cmdline(int argc, char **argv) | |||
1440 | 1594 | ||
1441 | progname = argv[0]; | 1595 | progname = argv[0]; |
1442 | 1596 | ||
1443 | while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) { | 1597 | while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) { |
1444 | switch (opt) { | 1598 | switch (opt) { |
1445 | case 'c': | 1599 | case 'p': |
1446 | show_core_only++; | 1600 | show_core_only++; |
1447 | break; | 1601 | break; |
1448 | case 'p': | 1602 | case 'P': |
1449 | show_pkg_only++; | 1603 | show_pkg_only++; |
1450 | break; | 1604 | break; |
1451 | case 's': | 1605 | case 'S': |
1452 | summary_only++; | 1606 | summary_only++; |
1453 | break; | 1607 | break; |
1454 | case 'v': | 1608 | case 'v': |
@@ -1457,10 +1611,20 @@ void cmdline(int argc, char **argv) | |||
1457 | case 'i': | 1611 | case 'i': |
1458 | interval_sec = atoi(optarg); | 1612 | interval_sec = atoi(optarg); |
1459 | break; | 1613 | break; |
1614 | case 'c': | ||
1615 | sscanf(optarg, "%x", &extra_delta_offset32); | ||
1616 | break; | ||
1617 | case 's': | ||
1618 | extra_delta_offset32 = 0x34; /* SMI counter */ | ||
1619 | break; | ||
1620 | case 'C': | ||
1621 | sscanf(optarg, "%x", &extra_delta_offset64); | ||
1622 | break; | ||
1623 | case 'm': | ||
1624 | sscanf(optarg, "%x", &extra_msr_offset32); | ||
1625 | break; | ||
1460 | case 'M': | 1626 | case 'M': |
1461 | sscanf(optarg, "%x", &extra_msr_offset); | 1627 | sscanf(optarg, "%x", &extra_msr_offset64); |
1462 | if (verbose > 1) | ||
1463 | fprintf(stderr, "MSR 0x%X\n", extra_msr_offset); | ||
1464 | break; | 1628 | break; |
1465 | default: | 1629 | default: |
1466 | usage(); | 1630 | usage(); |
@@ -1473,7 +1637,7 @@ int main(int argc, char **argv) | |||
1473 | cmdline(argc, argv); | 1637 | cmdline(argc, argv); |
1474 | 1638 | ||
1475 | if (verbose > 1) | 1639 | if (verbose > 1) |
1476 | fprintf(stderr, "turbostat v2.0 May 16, 2012" | 1640 | fprintf(stderr, "turbostat v2.1 October 6, 2012" |
1477 | " - Len Brown <lenb@kernel.org>\n"); | 1641 | " - Len Brown <lenb@kernel.org>\n"); |
1478 | 1642 | ||
1479 | turbostat_init(); | 1643 | turbostat_init(); |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index c05bcd293d8c..c7ba7614061b 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -1740,8 +1740,10 @@ sub install { | |||
1740 | open(IN, "$output_config") or dodie("Can't read config file"); | 1740 | open(IN, "$output_config") or dodie("Can't read config file"); |
1741 | while (<IN>) { | 1741 | while (<IN>) { |
1742 | if (/CONFIG_MODULES(=y)?/) { | 1742 | if (/CONFIG_MODULES(=y)?/) { |
1743 | $install_mods = 1 if (defined($1)); | 1743 | if (defined($1)) { |
1744 | last; | 1744 | $install_mods = 1; |
1745 | last; | ||
1746 | } | ||
1745 | } | 1747 | } |
1746 | } | 1748 | } |
1747 | close(IN); | 1749 | close(IN); |
@@ -1873,10 +1875,10 @@ sub make_oldconfig { | |||
1873 | apply_min_config; | 1875 | apply_min_config; |
1874 | } | 1876 | } |
1875 | 1877 | ||
1876 | if (!run_command "$make oldnoconfig") { | 1878 | if (!run_command "$make olddefconfig") { |
1877 | # Perhaps oldnoconfig doesn't exist in this version of the kernel | 1879 | # Perhaps olddefconfig doesn't exist in this version of the kernel |
1878 | # try a yes '' | oldconfig | 1880 | # try a yes '' | oldconfig |
1879 | doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; | 1881 | doprint "olddefconfig failed, trying yes '' | make oldconfig\n"; |
1880 | run_command "yes '' | $make oldconfig" or | 1882 | run_command "yes '' | $make oldconfig" or |
1881 | dodie "failed make config oldconfig"; | 1883 | dodie "failed make config oldconfig"; |
1882 | } | 1884 | } |
@@ -1929,7 +1931,7 @@ sub build { | |||
1929 | 1931 | ||
1930 | # old config can ask questions | 1932 | # old config can ask questions |
1931 | if ($type eq "oldconfig") { | 1933 | if ($type eq "oldconfig") { |
1932 | $type = "oldnoconfig"; | 1934 | $type = "olddefconfig"; |
1933 | 1935 | ||
1934 | # allow for empty configs | 1936 | # allow for empty configs |
1935 | run_command "touch $output_config"; | 1937 | run_command "touch $output_config"; |
@@ -1959,7 +1961,7 @@ sub build { | |||
1959 | load_force_config($minconfig); | 1961 | load_force_config($minconfig); |
1960 | } | 1962 | } |
1961 | 1963 | ||
1962 | if ($type ne "oldnoconfig") { | 1964 | if ($type ne "olddefconfig") { |
1963 | run_command "$make $type" or | 1965 | run_command "$make $type" or |
1964 | dodie "failed make config"; | 1966 | dodie "failed make config"; |
1965 | } | 1967 | } |
@@ -2458,8 +2460,7 @@ my %config_set; | |||
2458 | 2460 | ||
2459 | # config_off holds the set of configs that the bad config had disabled. | 2461 | # config_off holds the set of configs that the bad config had disabled. |
2460 | # We need to record them and set them in the .config when running | 2462 | # We need to record them and set them in the .config when running |
2461 | # oldnoconfig, because oldnoconfig does not turn off new symbols, but | 2463 | # olddefconfig, because olddefconfig keeps the defaults. |
2462 | # instead just keeps the defaults. | ||
2463 | my %config_off; | 2464 | my %config_off; |
2464 | 2465 | ||
2465 | # config_off_tmp holds a set of configs to turn off for now | 2466 | # config_off_tmp holds a set of configs to turn off for now |
@@ -3250,7 +3251,7 @@ sub test_this_config { | |||
3250 | } | 3251 | } |
3251 | 3252 | ||
3252 | # Remove this config from the list of configs | 3253 | # Remove this config from the list of configs |
3253 | # do a make oldnoconfig and then read the resulting | 3254 | # do a make olddefconfig and then read the resulting |
3254 | # .config to make sure it is missing the config that | 3255 | # .config to make sure it is missing the config that |
3255 | # we had before | 3256 | # we had before |
3256 | my %configs = %min_configs; | 3257 | my %configs = %min_configs; |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 85baf11e2acd..43480149119e 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug | 1 | TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll |
2 | 2 | ||
3 | all: | 3 | all: |
4 | for TARGET in $(TARGETS); do \ | 4 | for TARGET in $(TARGETS); do \ |
diff --git a/tools/testing/selftests/epoll/Makefile b/tools/testing/selftests/epoll/Makefile new file mode 100644 index 000000000000..19806ed62f50 --- /dev/null +++ b/tools/testing/selftests/epoll/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for epoll selftests | ||
2 | |||
3 | all: test_epoll | ||
4 | %: %.c | ||
5 | gcc -pthread -g -o $@ $^ | ||
6 | |||
7 | run_tests: all | ||
8 | ./test_epoll | ||
9 | |||
10 | clean: | ||
11 | $(RM) test_epoll | ||
diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c new file mode 100644 index 000000000000..f7525392ce84 --- /dev/null +++ b/tools/testing/selftests/epoll/test_epoll.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/epoll/test_epoll.c | ||
3 | * | ||
4 | * Copyright 2012 Adobe Systems Incorporated | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * Paton J. Lewis <palewis@adobe.com> | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <pthread.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <unistd.h> | ||
21 | #include <sys/epoll.h> | ||
22 | #include <sys/socket.h> | ||
23 | |||
24 | /* | ||
25 | * A pointer to an epoll_item_private structure will be stored in the epoll | ||
26 | * item's event structure so that we can get access to the epoll_item_private | ||
27 | * data after calling epoll_wait: | ||
28 | */ | ||
29 | struct epoll_item_private { | ||
30 | int index; /* Position of this struct within the epoll_items array. */ | ||
31 | int fd; | ||
32 | uint32_t events; | ||
33 | pthread_mutex_t mutex; /* Guards the following variables... */ | ||
34 | int stop; | ||
35 | int status; /* Stores any error encountered while handling item. */ | ||
36 | /* The following variable allows us to test whether we have encountered | ||
37 | a problem while attempting to cancel and delete the associated | ||
38 | event. When the test program exits, 'deleted' should be exactly | ||
39 | one. If it is greater than one, then the failed test reflects a real | ||
40 | world situation where we would have tried to access the epoll item's | ||
41 | private data after deleting it: */ | ||
42 | int deleted; | ||
43 | }; | ||
44 | |||
45 | struct epoll_item_private *epoll_items; | ||
46 | |||
47 | /* | ||
48 | * Delete the specified item from the epoll set. In a real-world secneario this | ||
49 | * is where we would free the associated data structure, but in this testing | ||
50 | * environment we retain the structure so that we can test for double-deletion: | ||
51 | */ | ||
52 | void delete_item(int index) | ||
53 | { | ||
54 | __sync_fetch_and_add(&epoll_items[index].deleted, 1); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * A pointer to a read_thread_data structure will be passed as the argument to | ||
59 | * each read thread: | ||
60 | */ | ||
61 | struct read_thread_data { | ||
62 | int stop; | ||
63 | int status; /* Indicates any error encountered by the read thread. */ | ||
64 | int epoll_set; | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * The function executed by the read threads: | ||
69 | */ | ||
70 | void *read_thread_function(void *function_data) | ||
71 | { | ||
72 | struct read_thread_data *thread_data = | ||
73 | (struct read_thread_data *)function_data; | ||
74 | struct epoll_event event_data; | ||
75 | struct epoll_item_private *item_data; | ||
76 | char socket_data; | ||
77 | |||
78 | /* Handle events until we encounter an error or this thread's 'stop' | ||
79 | condition is set: */ | ||
80 | while (1) { | ||
81 | int result = epoll_wait(thread_data->epoll_set, | ||
82 | &event_data, | ||
83 | 1, /* Number of desired events */ | ||
84 | 1000); /* Timeout in ms */ | ||
85 | if (result < 0) { | ||
86 | /* Breakpoints signal all threads. Ignore that while | ||
87 | debugging: */ | ||
88 | if (errno == EINTR) | ||
89 | continue; | ||
90 | thread_data->status = errno; | ||
91 | return 0; | ||
92 | } else if (thread_data->stop) | ||
93 | return 0; | ||
94 | else if (result == 0) /* Timeout */ | ||
95 | continue; | ||
96 | |||
97 | /* We need the mutex here because checking for the stop | ||
98 | condition and re-enabling the epoll item need to be done | ||
99 | together as one atomic operation when EPOLL_CTL_DISABLE is | ||
100 | available: */ | ||
101 | item_data = (struct epoll_item_private *)event_data.data.ptr; | ||
102 | pthread_mutex_lock(&item_data->mutex); | ||
103 | |||
104 | /* Remove the item from the epoll set if we want to stop | ||
105 | handling that event: */ | ||
106 | if (item_data->stop) | ||
107 | delete_item(item_data->index); | ||
108 | else { | ||
109 | /* Clear the data that was written to the other end of | ||
110 | our non-blocking socket: */ | ||
111 | do { | ||
112 | if (read(item_data->fd, &socket_data, 1) < 1) { | ||
113 | if ((errno == EAGAIN) || | ||
114 | (errno == EWOULDBLOCK)) | ||
115 | break; | ||
116 | else | ||
117 | goto error_unlock; | ||
118 | } | ||
119 | } while (item_data->events & EPOLLET); | ||
120 | |||
121 | /* The item was one-shot, so re-enable it: */ | ||
122 | event_data.events = item_data->events; | ||
123 | if (epoll_ctl(thread_data->epoll_set, | ||
124 | EPOLL_CTL_MOD, | ||
125 | item_data->fd, | ||
126 | &event_data) < 0) | ||
127 | goto error_unlock; | ||
128 | } | ||
129 | |||
130 | pthread_mutex_unlock(&item_data->mutex); | ||
131 | } | ||
132 | |||
133 | error_unlock: | ||
134 | thread_data->status = item_data->status = errno; | ||
135 | pthread_mutex_unlock(&item_data->mutex); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * A pointer to a write_thread_data structure will be passed as the argument to | ||
141 | * the write thread: | ||
142 | */ | ||
143 | struct write_thread_data { | ||
144 | int stop; | ||
145 | int status; /* Indicates any error encountered by the write thread. */ | ||
146 | int n_fds; | ||
147 | int *fds; | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * The function executed by the write thread. It writes a single byte to each | ||
152 | * socket in turn until the stop condition for this thread is set. If writing to | ||
153 | * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for | ||
154 | * the moment and just move on to the next socket in the list. We don't care | ||
155 | * about the order in which we deliver events to the epoll set. In fact we don't | ||
156 | * care about the data we're writing to the pipes at all; we just want to | ||
157 | * trigger epoll events: | ||
158 | */ | ||
159 | void *write_thread_function(void *function_data) | ||
160 | { | ||
161 | const char data = 'X'; | ||
162 | int index; | ||
163 | struct write_thread_data *thread_data = | ||
164 | (struct write_thread_data *)function_data; | ||
165 | while (!thread_data->stop) | ||
166 | for (index = 0; | ||
167 | !thread_data->stop && (index < thread_data->n_fds); | ||
168 | ++index) | ||
169 | if ((write(thread_data->fds[index], &data, 1) < 1) && | ||
170 | (errno != EAGAIN) && | ||
171 | (errno != EWOULDBLOCK)) { | ||
172 | thread_data->status = errno; | ||
173 | return; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Arguments are currently ignored: | ||
179 | */ | ||
180 | int main(int argc, char **argv) | ||
181 | { | ||
182 | const int n_read_threads = 100; | ||
183 | const int n_epoll_items = 500; | ||
184 | int index; | ||
185 | int epoll_set = epoll_create1(0); | ||
186 | struct write_thread_data write_thread_data = { | ||
187 | 0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int)) | ||
188 | }; | ||
189 | struct read_thread_data *read_thread_data = | ||
190 | malloc(n_read_threads * sizeof(struct read_thread_data)); | ||
191 | pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t)); | ||
192 | pthread_t write_thread; | ||
193 | |||
194 | printf("-----------------\n"); | ||
195 | printf("Runing test_epoll\n"); | ||
196 | printf("-----------------\n"); | ||
197 | |||
198 | epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private)); | ||
199 | |||
200 | if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 || | ||
201 | read_thread_data == 0 || read_threads == 0) | ||
202 | goto error; | ||
203 | |||
204 | if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { | ||
205 | printf("Error: please run this test on a multi-core system.\n"); | ||
206 | goto error; | ||
207 | } | ||
208 | |||
209 | /* Create the socket pairs and epoll items: */ | ||
210 | for (index = 0; index < n_epoll_items; ++index) { | ||
211 | int socket_pair[2]; | ||
212 | struct epoll_event event_data; | ||
213 | if (socketpair(AF_UNIX, | ||
214 | SOCK_STREAM | SOCK_NONBLOCK, | ||
215 | 0, | ||
216 | socket_pair) < 0) | ||
217 | goto error; | ||
218 | write_thread_data.fds[index] = socket_pair[0]; | ||
219 | epoll_items[index].index = index; | ||
220 | epoll_items[index].fd = socket_pair[1]; | ||
221 | if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0) | ||
222 | goto error; | ||
223 | /* We always use EPOLLONESHOT because this test is currently | ||
224 | structured to demonstrate the need for EPOLL_CTL_DISABLE, | ||
225 | which only produces useful information in the EPOLLONESHOT | ||
226 | case (without EPOLLONESHOT, calling epoll_ctl with | ||
227 | EPOLL_CTL_DISABLE will never return EBUSY). If support for | ||
228 | testing events without EPOLLONESHOT is desired, it should | ||
229 | probably be implemented in a separate unit test. */ | ||
230 | epoll_items[index].events = EPOLLIN | EPOLLONESHOT; | ||
231 | if (index < n_epoll_items / 2) | ||
232 | epoll_items[index].events |= EPOLLET; | ||
233 | epoll_items[index].stop = 0; | ||
234 | epoll_items[index].status = 0; | ||
235 | epoll_items[index].deleted = 0; | ||
236 | event_data.events = epoll_items[index].events; | ||
237 | event_data.data.ptr = &epoll_items[index]; | ||
238 | if (epoll_ctl(epoll_set, | ||
239 | EPOLL_CTL_ADD, | ||
240 | epoll_items[index].fd, | ||
241 | &event_data) < 0) | ||
242 | goto error; | ||
243 | } | ||
244 | |||
245 | /* Create and start the read threads: */ | ||
246 | for (index = 0; index < n_read_threads; ++index) { | ||
247 | read_thread_data[index].stop = 0; | ||
248 | read_thread_data[index].status = 0; | ||
249 | read_thread_data[index].epoll_set = epoll_set; | ||
250 | if (pthread_create(&read_threads[index], | ||
251 | NULL, | ||
252 | read_thread_function, | ||
253 | &read_thread_data[index]) != 0) | ||
254 | goto error; | ||
255 | } | ||
256 | |||
257 | if (pthread_create(&write_thread, | ||
258 | NULL, | ||
259 | write_thread_function, | ||
260 | &write_thread_data) != 0) | ||
261 | goto error; | ||
262 | |||
263 | /* Cancel all event pollers: */ | ||
264 | #ifdef EPOLL_CTL_DISABLE | ||
265 | for (index = 0; index < n_epoll_items; ++index) { | ||
266 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
267 | ++epoll_items[index].stop; | ||
268 | if (epoll_ctl(epoll_set, | ||
269 | EPOLL_CTL_DISABLE, | ||
270 | epoll_items[index].fd, | ||
271 | NULL) == 0) | ||
272 | delete_item(index); | ||
273 | else if (errno != EBUSY) { | ||
274 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
275 | goto error; | ||
276 | } | ||
277 | /* EBUSY means events were being handled; allow the other thread | ||
278 | to delete the item. */ | ||
279 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
280 | } | ||
281 | #else | ||
282 | for (index = 0; index < n_epoll_items; ++index) { | ||
283 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
284 | ++epoll_items[index].stop; | ||
285 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
286 | /* Wait in case a thread running read_thread_function is | ||
287 | currently executing code between epoll_wait and | ||
288 | pthread_mutex_lock with this item. Note that a longer delay | ||
289 | would make double-deletion less likely (at the expense of | ||
290 | performance), but there is no guarantee that any delay would | ||
291 | ever be sufficient. Note also that we delete all event | ||
292 | pollers at once for testing purposes, but in a real-world | ||
293 | environment we are likely to want to be able to cancel event | ||
294 | pollers at arbitrary times. Therefore we can't improve this | ||
295 | situation by just splitting this loop into two loops | ||
296 | (i.e. signal 'stop' for all items, sleep, and then delete all | ||
297 | items). We also can't fix the problem via EPOLL_CTL_DEL | ||
298 | because that command can't prevent the case where some other | ||
299 | thread is executing read_thread_function within the region | ||
300 | mentioned above: */ | ||
301 | usleep(1); | ||
302 | pthread_mutex_lock(&epoll_items[index].mutex); | ||
303 | if (!epoll_items[index].deleted) | ||
304 | delete_item(index); | ||
305 | pthread_mutex_unlock(&epoll_items[index].mutex); | ||
306 | } | ||
307 | #endif | ||
308 | |||
309 | /* Shut down the read threads: */ | ||
310 | for (index = 0; index < n_read_threads; ++index) | ||
311 | __sync_fetch_and_add(&read_thread_data[index].stop, 1); | ||
312 | for (index = 0; index < n_read_threads; ++index) { | ||
313 | if (pthread_join(read_threads[index], NULL) != 0) | ||
314 | goto error; | ||
315 | if (read_thread_data[index].status) | ||
316 | goto error; | ||
317 | } | ||
318 | |||
319 | /* Shut down the write thread: */ | ||
320 | __sync_fetch_and_add(&write_thread_data.stop, 1); | ||
321 | if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status) | ||
322 | goto error; | ||
323 | |||
324 | /* Check for final error conditions: */ | ||
325 | for (index = 0; index < n_epoll_items; ++index) { | ||
326 | if (epoll_items[index].status != 0) | ||
327 | goto error; | ||
328 | if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0) | ||
329 | goto error; | ||
330 | } | ||
331 | for (index = 0; index < n_epoll_items; ++index) | ||
332 | if (epoll_items[index].deleted != 1) { | ||
333 | printf("Error: item data deleted %1d times.\n", | ||
334 | epoll_items[index].deleted); | ||
335 | goto error; | ||
336 | } | ||
337 | |||
338 | printf("[PASS]\n"); | ||
339 | return 0; | ||
340 | |||
341 | error: | ||
342 | printf("[FAIL]\n"); | ||
343 | return errno; | ||
344 | } | ||
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index b0adb2710c02..68d0734b2081 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c | |||
@@ -253,9 +253,6 @@ static int find_testdev(const char *name, const struct stat *sb, int flag) | |||
253 | 253 | ||
254 | if (flag != FTW_F) | 254 | if (flag != FTW_F) |
255 | return 0; | 255 | return 0; |
256 | /* ignore /proc/bus/usb/{devices,drivers} */ | ||
257 | if (strrchr(name, '/')[1] == 'd') | ||
258 | return 0; | ||
259 | 256 | ||
260 | fd = fopen(name, "rb"); | 257 | fd = fopen(name, "rb"); |
261 | if (!fd) { | 258 | if (!fd) { |
@@ -356,28 +353,8 @@ restart: | |||
356 | 353 | ||
357 | static const char *usbfs_dir_find(void) | 354 | static const char *usbfs_dir_find(void) |
358 | { | 355 | { |
359 | static char usbfs_path_0[] = "/dev/usb/devices"; | ||
360 | static char usbfs_path_1[] = "/proc/bus/usb/devices"; | ||
361 | static char udev_usb_path[] = "/dev/bus/usb"; | 356 | static char udev_usb_path[] = "/dev/bus/usb"; |
362 | 357 | ||
363 | static char *const usbfs_paths[] = { | ||
364 | usbfs_path_0, usbfs_path_1 | ||
365 | }; | ||
366 | |||
367 | static char *const * | ||
368 | end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths; | ||
369 | |||
370 | char *const *it = usbfs_paths; | ||
371 | do { | ||
372 | int fd = open(*it, O_RDONLY); | ||
373 | close(fd); | ||
374 | if (fd >= 0) { | ||
375 | strrchr(*it, '/')[0] = '\0'; | ||
376 | return *it; | ||
377 | } | ||
378 | } while (++it != end); | ||
379 | |||
380 | /* real device-nodes managed by udev */ | ||
381 | if (access(udev_usb_path, F_OK) == 0) | 358 | if (access(udev_usb_path, F_OK) == 0) |
382 | return udev_usb_path; | 359 | return udev_usb_path; |
383 | 360 | ||
@@ -489,7 +466,7 @@ usage: | |||
489 | goto usage; | 466 | goto usage; |
490 | if (!all && !device) { | 467 | if (!all && !device) { |
491 | fprintf (stderr, "must specify '-a' or '-D dev', " | 468 | fprintf (stderr, "must specify '-a' or '-D dev', " |
492 | "or DEVICE=/proc/bus/usb/BBB/DDD in env\n"); | 469 | "or DEVICE=/dev/bus/usb/BBB/DDD in env\n"); |
493 | goto usage; | 470 | goto usage; |
494 | } | 471 | } |
495 | 472 | ||
diff --git a/tools/virtio/virtio-trace/Makefile b/tools/virtio/virtio-trace/Makefile new file mode 100644 index 000000000000..0d2381633475 --- /dev/null +++ b/tools/virtio/virtio-trace/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | CC = gcc | ||
2 | CFLAGS = -O2 -Wall -pthread | ||
3 | |||
4 | all: trace-agent | ||
5 | |||
6 | .c.o: | ||
7 | $(CC) $(CFLAGS) -c $^ -o $@ | ||
8 | |||
9 | trace-agent: trace-agent.o trace-agent-ctl.o trace-agent-rw.o | ||
10 | $(CC) $(CFLAGS) -o $@ $^ | ||
11 | |||
12 | clean: | ||
13 | rm -f *.o trace-agent | ||
diff --git a/tools/virtio/virtio-trace/README b/tools/virtio/virtio-trace/README new file mode 100644 index 000000000000..b64845b823ab --- /dev/null +++ b/tools/virtio/virtio-trace/README | |||
@@ -0,0 +1,118 @@ | |||
1 | Trace Agent for virtio-trace | ||
2 | ============================ | ||
3 | |||
4 | Trace agent is a user tool for sending trace data of a guest to a Host in low | ||
5 | overhead. Trace agent has the following functions: | ||
6 | - splice a page of ring-buffer to read_pipe without memory copying | ||
7 | - splice the page from write_pipe to virtio-console without memory copying | ||
8 | - write trace data to stdout by using -o option | ||
9 | - controlled by start/stop orders from a Host | ||
10 | |||
11 | The trace agent operates as follows: | ||
12 | 1) Initialize all structures. | ||
13 | 2) Create a read/write thread per CPU. Each thread is bound to a CPU. | ||
14 | The read/write threads hold it. | ||
15 | 3) A controller thread does poll() for a start order of a host. | ||
16 | 4) After the controller of the trace agent receives a start order from a host, | ||
17 | the controller wake read/write threads. | ||
18 | 5) The read/write threads start to read trace data from ring-buffers and | ||
19 | write the data to virtio-serial. | ||
20 | 6) If the controller receives a stop order from a host, the read/write threads | ||
21 | stop to read trace data. | ||
22 | |||
23 | |||
24 | Files | ||
25 | ===== | ||
26 | |||
27 | README: this file | ||
28 | Makefile: Makefile of trace agent for virtio-trace | ||
29 | trace-agent.c: includes main function, sets up for operating trace agent | ||
30 | trace-agent.h: includes all structures and some macros | ||
31 | trace-agent-ctl.c: includes controller function for read/write threads | ||
32 | trace-agent-rw.c: includes read/write threads function | ||
33 | |||
34 | |||
35 | Setup | ||
36 | ===== | ||
37 | |||
38 | To use this trace agent for virtio-trace, we need to prepare some virtio-serial | ||
39 | I/Fs. | ||
40 | |||
41 | 1) Make FIFO in a host | ||
42 | virtio-trace uses virtio-serial pipe as trace data paths as to the number | ||
43 | of CPUs and a control path, so FIFO (named pipe) should be created as follows: | ||
44 | # mkdir /tmp/virtio-trace/ | ||
45 | # mkfifo /tmp/virtio-trace/trace-path-cpu{0,1,2,...,X}.{in,out} | ||
46 | # mkfifo /tmp/virtio-trace/agent-ctl-path.{in,out} | ||
47 | |||
48 | For example, if a guest use three CPUs, the names are | ||
49 | trace-path-cpu{0,1,2}.{in.out} | ||
50 | and | ||
51 | agent-ctl-path.{in,out}. | ||
52 | |||
53 | 2) Set up of virtio-serial pipe in a host | ||
54 | Add qemu option to use virtio-serial pipe. | ||
55 | |||
56 | ##virtio-serial device## | ||
57 | -device virtio-serial-pci,id=virtio-serial0\ | ||
58 | ##control path## | ||
59 | -chardev pipe,id=charchannel0,path=/tmp/virtio-trace/agent-ctl-path\ | ||
60 | -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,\ | ||
61 | id=channel0,name=agent-ctl-path\ | ||
62 | ##data path## | ||
63 | -chardev pipe,id=charchannel1,path=/tmp/virtio-trace/trace-path-cpu0\ | ||
64 | -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel0,\ | ||
65 | id=channel1,name=trace-path-cpu0\ | ||
66 | ... | ||
67 | |||
68 | If you manage guests with libvirt, add the following tags to domain XML files. | ||
69 | Then, libvirt passes the same command option to qemu. | ||
70 | |||
71 | <channel type='pipe'> | ||
72 | <source path='/tmp/virtio-trace/agent-ctl-path'/> | ||
73 | <target type='virtio' name='agent-ctl-path'/> | ||
74 | <address type='virtio-serial' controller='0' bus='0' port='0'/> | ||
75 | </channel> | ||
76 | <channel type='pipe'> | ||
77 | <source path='/tmp/virtio-trace/trace-path-cpu0'/> | ||
78 | <target type='virtio' name='trace-path-cpu0'/> | ||
79 | <address type='virtio-serial' controller='0' bus='0' port='1'/> | ||
80 | </channel> | ||
81 | ... | ||
82 | Here, chardev names are restricted to trace-path-cpuX and agent-ctl-path. For | ||
83 | example, if a guest use three CPUs, chardev names should be trace-path-cpu0, | ||
84 | trace-path-cpu1, trace-path-cpu2, and agent-ctl-path. | ||
85 | |||
86 | 3) Boot the guest | ||
87 | You can find some chardev in /dev/virtio-ports/ in the guest. | ||
88 | |||
89 | |||
90 | Run | ||
91 | === | ||
92 | |||
93 | 0) Build trace agent in a guest | ||
94 | $ make | ||
95 | |||
96 | 1) Enable ftrace in the guest | ||
97 | <Example> | ||
98 | # echo 1 > /sys/kernel/debug/tracing/events/sched/enable | ||
99 | |||
100 | 2) Run trace agent in the guest | ||
101 | This agent must be operated as root. | ||
102 | # ./trace-agent | ||
103 | read/write threads in the agent wait for start order from host. If you add -o | ||
104 | option, trace data are output via stdout in the guest. | ||
105 | |||
106 | 3) Open FIFO in a host | ||
107 | # cat /tmp/virtio-trace/trace-path-cpu0.out | ||
108 | If a host does not open these, trace data get stuck in buffers of virtio. Then, | ||
109 | the guest will stop by specification of chardev in QEMU. This blocking mode may | ||
110 | be solved in the future. | ||
111 | |||
112 | 4) Start to read trace data by ordering from a host | ||
113 | A host injects read start order to the guest via virtio-serial. | ||
114 | # echo 1 > /tmp/virtio-trace/agent-ctl-path.in | ||
115 | |||
116 | 5) Stop to read trace data by ordering from a host | ||
117 | A host injects read stop order to the guest via virtio-serial. | ||
118 | # echo 0 > /tmp/virtio-trace/agent-ctl-path.in | ||
diff --git a/tools/virtio/virtio-trace/trace-agent-ctl.c b/tools/virtio/virtio-trace/trace-agent-ctl.c new file mode 100644 index 000000000000..a2d0403c4f94 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent-ctl.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Controller of read/write threads for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <fcntl.h> | ||
14 | #include <poll.h> | ||
15 | #include <signal.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <unistd.h> | ||
19 | #include "trace-agent.h" | ||
20 | |||
21 | #define HOST_MSG_SIZE 256 | ||
22 | #define EVENT_WAIT_MSEC 100 | ||
23 | |||
24 | static volatile sig_atomic_t global_signal_val; | ||
25 | bool global_sig_receive; /* default false */ | ||
26 | bool global_run_operation; /* default false*/ | ||
27 | |||
28 | /* Handle SIGTERM/SIGINT/SIGQUIT to exit */ | ||
29 | static void signal_handler(int sig) | ||
30 | { | ||
31 | global_signal_val = sig; | ||
32 | } | ||
33 | |||
34 | int rw_ctl_init(const char *ctl_path) | ||
35 | { | ||
36 | int ctl_fd; | ||
37 | |||
38 | ctl_fd = open(ctl_path, O_RDONLY); | ||
39 | if (ctl_fd == -1) { | ||
40 | pr_err("Cannot open ctl_fd\n"); | ||
41 | goto error; | ||
42 | } | ||
43 | |||
44 | return ctl_fd; | ||
45 | |||
46 | error: | ||
47 | exit(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | static int wait_order(int ctl_fd) | ||
51 | { | ||
52 | struct pollfd poll_fd; | ||
53 | int ret = 0; | ||
54 | |||
55 | while (!global_sig_receive) { | ||
56 | poll_fd.fd = ctl_fd; | ||
57 | poll_fd.events = POLLIN; | ||
58 | |||
59 | ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC); | ||
60 | |||
61 | if (global_signal_val) { | ||
62 | global_sig_receive = true; | ||
63 | pr_info("Receive interrupt %d\n", global_signal_val); | ||
64 | |||
65 | /* Wakes rw-threads when they are sleeping */ | ||
66 | if (!global_run_operation) | ||
67 | pthread_cond_broadcast(&cond_wakeup); | ||
68 | |||
69 | ret = -1; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | if (ret < 0) { | ||
74 | pr_err("Polling error\n"); | ||
75 | goto error; | ||
76 | } | ||
77 | |||
78 | if (ret) | ||
79 | break; | ||
80 | }; | ||
81 | |||
82 | return ret; | ||
83 | |||
84 | error: | ||
85 | exit(EXIT_FAILURE); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * contol read/write threads by handling global_run_operation | ||
90 | */ | ||
91 | void *rw_ctl_loop(int ctl_fd) | ||
92 | { | ||
93 | ssize_t rlen; | ||
94 | char buf[HOST_MSG_SIZE]; | ||
95 | int ret; | ||
96 | |||
97 | /* Setup signal handlers */ | ||
98 | signal(SIGTERM, signal_handler); | ||
99 | signal(SIGINT, signal_handler); | ||
100 | signal(SIGQUIT, signal_handler); | ||
101 | |||
102 | while (!global_sig_receive) { | ||
103 | |||
104 | ret = wait_order(ctl_fd); | ||
105 | if (ret < 0) | ||
106 | break; | ||
107 | |||
108 | rlen = read(ctl_fd, buf, sizeof(buf)); | ||
109 | if (rlen < 0) { | ||
110 | pr_err("read data error in ctl thread\n"); | ||
111 | goto error; | ||
112 | } | ||
113 | |||
114 | if (rlen == 2 && buf[0] == '1') { | ||
115 | /* | ||
116 | * If host writes '1' to a control path, | ||
117 | * this controller wakes all read/write threads. | ||
118 | */ | ||
119 | global_run_operation = true; | ||
120 | pthread_cond_broadcast(&cond_wakeup); | ||
121 | pr_debug("Wake up all read/write threads\n"); | ||
122 | } else if (rlen == 2 && buf[0] == '0') { | ||
123 | /* | ||
124 | * If host writes '0' to a control path, read/write | ||
125 | * threads will wait for notification from Host. | ||
126 | */ | ||
127 | global_run_operation = false; | ||
128 | pr_debug("Stop all read/write threads\n"); | ||
129 | } else | ||
130 | pr_info("Invalid host notification: %s\n", buf); | ||
131 | } | ||
132 | |||
133 | return NULL; | ||
134 | |||
135 | error: | ||
136 | exit(EXIT_FAILURE); | ||
137 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent-rw.c b/tools/virtio/virtio-trace/trace-agent-rw.c new file mode 100644 index 000000000000..3aace5ea4842 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent-rw.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Read/write thread of a guest agent for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <fcntl.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | #include <sys/syscall.h> | ||
18 | #include "trace-agent.h" | ||
19 | |||
20 | #define READ_WAIT_USEC 100000 | ||
21 | |||
22 | void *rw_thread_info_new(void) | ||
23 | { | ||
24 | struct rw_thread_info *rw_ti; | ||
25 | |||
26 | rw_ti = zalloc(sizeof(struct rw_thread_info)); | ||
27 | if (rw_ti == NULL) { | ||
28 | pr_err("rw_thread_info zalloc error\n"); | ||
29 | exit(EXIT_FAILURE); | ||
30 | } | ||
31 | |||
32 | rw_ti->cpu_num = -1; | ||
33 | rw_ti->in_fd = -1; | ||
34 | rw_ti->out_fd = -1; | ||
35 | rw_ti->read_pipe = -1; | ||
36 | rw_ti->write_pipe = -1; | ||
37 | rw_ti->pipe_size = PIPE_INIT; | ||
38 | |||
39 | return rw_ti; | ||
40 | } | ||
41 | |||
42 | void *rw_thread_init(int cpu, const char *in_path, const char *out_path, | ||
43 | bool stdout_flag, unsigned long pipe_size, | ||
44 | struct rw_thread_info *rw_ti) | ||
45 | { | ||
46 | int data_pipe[2]; | ||
47 | |||
48 | rw_ti->cpu_num = cpu; | ||
49 | |||
50 | /* set read(input) fd */ | ||
51 | rw_ti->in_fd = open(in_path, O_RDONLY); | ||
52 | if (rw_ti->in_fd == -1) { | ||
53 | pr_err("Could not open in_fd (CPU:%d)\n", cpu); | ||
54 | goto error; | ||
55 | } | ||
56 | |||
57 | /* set write(output) fd */ | ||
58 | if (!stdout_flag) { | ||
59 | /* virtio-serial output mode */ | ||
60 | rw_ti->out_fd = open(out_path, O_WRONLY); | ||
61 | if (rw_ti->out_fd == -1) { | ||
62 | pr_err("Could not open out_fd (CPU:%d)\n", cpu); | ||
63 | goto error; | ||
64 | } | ||
65 | } else | ||
66 | /* stdout mode */ | ||
67 | rw_ti->out_fd = STDOUT_FILENO; | ||
68 | |||
69 | if (pipe2(data_pipe, O_NONBLOCK) < 0) { | ||
70 | pr_err("Could not create pipe in rw-thread(%d)\n", cpu); | ||
71 | goto error; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Size of pipe is 64kB in default based on fs/pipe.c. | ||
76 | * To read/write trace data speedy, pipe size is changed. | ||
77 | */ | ||
78 | if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) { | ||
79 | pr_err("Could not change pipe size in rw-thread(%d)\n", cpu); | ||
80 | goto error; | ||
81 | } | ||
82 | |||
83 | rw_ti->read_pipe = data_pipe[1]; | ||
84 | rw_ti->write_pipe = data_pipe[0]; | ||
85 | rw_ti->pipe_size = pipe_size; | ||
86 | |||
87 | return NULL; | ||
88 | |||
89 | error: | ||
90 | exit(EXIT_FAILURE); | ||
91 | } | ||
92 | |||
93 | /* Bind a thread to a cpu */ | ||
94 | static void bind_cpu(int cpu_num) | ||
95 | { | ||
96 | cpu_set_t mask; | ||
97 | |||
98 | CPU_ZERO(&mask); | ||
99 | CPU_SET(cpu_num, &mask); | ||
100 | |||
101 | /* bind my thread to cpu_num by assigning zero to the first argument */ | ||
102 | if (sched_setaffinity(0, sizeof(mask), &mask) == -1) | ||
103 | pr_err("Could not set CPU#%d affinity\n", (int)cpu_num); | ||
104 | } | ||
105 | |||
106 | static void *rw_thread_main(void *thread_info) | ||
107 | { | ||
108 | ssize_t rlen, wlen; | ||
109 | ssize_t ret; | ||
110 | struct rw_thread_info *ts = (struct rw_thread_info *)thread_info; | ||
111 | |||
112 | bind_cpu(ts->cpu_num); | ||
113 | |||
114 | while (1) { | ||
115 | /* Wait for a read order of trace data by Host OS */ | ||
116 | if (!global_run_operation) { | ||
117 | pthread_mutex_lock(&mutex_notify); | ||
118 | pthread_cond_wait(&cond_wakeup, &mutex_notify); | ||
119 | pthread_mutex_unlock(&mutex_notify); | ||
120 | } | ||
121 | |||
122 | if (global_sig_receive) | ||
123 | break; | ||
124 | |||
125 | /* | ||
126 | * Each thread read trace_pipe_raw of each cpu bounding the | ||
127 | * thread, so contention of multi-threads does not occur. | ||
128 | */ | ||
129 | rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL, | ||
130 | ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE); | ||
131 | |||
132 | if (rlen < 0) { | ||
133 | pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num); | ||
134 | goto error; | ||
135 | } else if (rlen == 0) { | ||
136 | /* | ||
137 | * If trace data do not exist or are unreadable not | ||
138 | * for exceeding the page size, splice_read returns | ||
139 | * NULL. Then, this waits for being filled the data in a | ||
140 | * ring-buffer. | ||
141 | */ | ||
142 | usleep(READ_WAIT_USEC); | ||
143 | pr_debug("Read retry(cpu:%d)\n", ts->cpu_num); | ||
144 | continue; | ||
145 | } | ||
146 | |||
147 | wlen = 0; | ||
148 | |||
149 | do { | ||
150 | ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL, | ||
151 | rlen - wlen, | ||
152 | SPLICE_F_MOVE | SPLICE_F_MORE); | ||
153 | |||
154 | if (ret < 0) { | ||
155 | pr_err("Splice_write in rw-thread(%d)\n", | ||
156 | ts->cpu_num); | ||
157 | goto error; | ||
158 | } else if (ret == 0) | ||
159 | /* | ||
160 | * When host reader is not in time for reading | ||
161 | * trace data, guest will be stopped. This is | ||
162 | * because char dev in QEMU is not supported | ||
163 | * non-blocking mode. Then, writer might be | ||
164 | * sleep in that case. | ||
165 | * This sleep will be removed by supporting | ||
166 | * non-blocking mode. | ||
167 | */ | ||
168 | sleep(1); | ||
169 | wlen += ret; | ||
170 | } while (wlen < rlen); | ||
171 | } | ||
172 | |||
173 | return NULL; | ||
174 | |||
175 | error: | ||
176 | exit(EXIT_FAILURE); | ||
177 | } | ||
178 | |||
179 | |||
180 | pthread_t rw_thread_run(struct rw_thread_info *rw_ti) | ||
181 | { | ||
182 | int ret; | ||
183 | pthread_t rw_thread_per_cpu; | ||
184 | |||
185 | ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti); | ||
186 | if (ret != 0) { | ||
187 | pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num); | ||
188 | exit(EXIT_FAILURE); | ||
189 | } | ||
190 | |||
191 | return rw_thread_per_cpu; | ||
192 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent.c b/tools/virtio/virtio-trace/trace-agent.c new file mode 100644 index 000000000000..0a0a7dd4eff7 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * Guest agent for virtio-trace | ||
3 | * | ||
4 | * Copyright (C) 2012 Hitachi, Ltd. | ||
5 | * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com> | ||
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | * | ||
8 | * Licensed under GPL version 2 only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <limits.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | #include "trace-agent.h" | ||
18 | |||
19 | #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE)) | ||
20 | #define PIPE_DEF_BUFS 16 | ||
21 | #define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS) | ||
22 | #define PIPE_MAX_SIZE (1024*1024) | ||
23 | #define READ_PATH_FMT \ | ||
24 | "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw" | ||
25 | #define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d" | ||
26 | #define CTL_PATH "/dev/virtio-ports/agent-ctl-path" | ||
27 | |||
28 | pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER; | ||
29 | pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER; | ||
30 | |||
31 | static int get_total_cpus(void) | ||
32 | { | ||
33 | int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF); | ||
34 | |||
35 | if (nr_cpus <= 0) { | ||
36 | pr_err("Could not read cpus\n"); | ||
37 | goto error; | ||
38 | } else if (nr_cpus > MAX_CPUS) { | ||
39 | pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS); | ||
40 | goto error; | ||
41 | } | ||
42 | |||
43 | return nr_cpus; | ||
44 | |||
45 | error: | ||
46 | exit(EXIT_FAILURE); | ||
47 | } | ||
48 | |||
49 | static void *agent_info_new(void) | ||
50 | { | ||
51 | struct agent_info *s; | ||
52 | int i; | ||
53 | |||
54 | s = zalloc(sizeof(struct agent_info)); | ||
55 | if (s == NULL) { | ||
56 | pr_err("agent_info zalloc error\n"); | ||
57 | exit(EXIT_FAILURE); | ||
58 | } | ||
59 | |||
60 | s->pipe_size = PIPE_INIT; | ||
61 | s->use_stdout = false; | ||
62 | s->cpus = get_total_cpus(); | ||
63 | s->ctl_fd = -1; | ||
64 | |||
65 | /* read/write threads init */ | ||
66 | for (i = 0; i < s->cpus; i++) | ||
67 | s->rw_ti[i] = rw_thread_info_new(); | ||
68 | |||
69 | return s; | ||
70 | } | ||
71 | |||
72 | static unsigned long parse_size(const char *arg) | ||
73 | { | ||
74 | unsigned long value, round; | ||
75 | char *ptr; | ||
76 | |||
77 | value = strtoul(arg, &ptr, 10); | ||
78 | switch (*ptr) { | ||
79 | case 'K': case 'k': | ||
80 | value <<= 10; | ||
81 | break; | ||
82 | case 'M': case 'm': | ||
83 | value <<= 20; | ||
84 | break; | ||
85 | default: | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | if (value > PIPE_MAX_SIZE) { | ||
90 | pr_err("Pipe size must be less than 1MB\n"); | ||
91 | goto error; | ||
92 | } else if (value < PIPE_MIN_SIZE) { | ||
93 | pr_err("Pipe size must be over 64KB\n"); | ||
94 | goto error; | ||
95 | } | ||
96 | |||
97 | /* Align buffer size with page unit */ | ||
98 | round = value & (PAGE_SIZE - 1); | ||
99 | value = value - round; | ||
100 | |||
101 | return value; | ||
102 | error: | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void usage(char const *prg) | ||
107 | { | ||
108 | pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg); | ||
109 | } | ||
110 | |||
111 | static const char *make_path(int cpu_num, bool this_is_write_path) | ||
112 | { | ||
113 | int ret; | ||
114 | char *buf; | ||
115 | |||
116 | buf = zalloc(PATH_MAX); | ||
117 | if (buf == NULL) { | ||
118 | pr_err("Could not allocate buffer\n"); | ||
119 | goto error; | ||
120 | } | ||
121 | |||
122 | if (this_is_write_path) | ||
123 | /* write(output) path */ | ||
124 | ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num); | ||
125 | else | ||
126 | /* read(input) path */ | ||
127 | ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num); | ||
128 | |||
129 | if (ret <= 0) { | ||
130 | pr_err("Failed to generate %s path(CPU#%d):%d\n", | ||
131 | this_is_write_path ? "read" : "write", cpu_num, ret); | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | return buf; | ||
136 | |||
137 | error: | ||
138 | free(buf); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | static const char *make_input_path(int cpu_num) | ||
143 | { | ||
144 | return make_path(cpu_num, false); | ||
145 | } | ||
146 | |||
147 | static const char *make_output_path(int cpu_num) | ||
148 | { | ||
149 | return make_path(cpu_num, true); | ||
150 | } | ||
151 | |||
152 | static void *agent_info_init(struct agent_info *s) | ||
153 | { | ||
154 | int cpu; | ||
155 | const char *in_path = NULL; | ||
156 | const char *out_path = NULL; | ||
157 | |||
158 | /* init read/write threads */ | ||
159 | for (cpu = 0; cpu < s->cpus; cpu++) { | ||
160 | /* set read(input) path per read/write thread */ | ||
161 | in_path = make_input_path(cpu); | ||
162 | if (in_path == NULL) | ||
163 | goto error; | ||
164 | |||
165 | /* set write(output) path per read/write thread*/ | ||
166 | if (!s->use_stdout) { | ||
167 | out_path = make_output_path(cpu); | ||
168 | if (out_path == NULL) | ||
169 | goto error; | ||
170 | } else | ||
171 | /* stdout mode */ | ||
172 | pr_debug("stdout mode\n"); | ||
173 | |||
174 | rw_thread_init(cpu, in_path, out_path, s->use_stdout, | ||
175 | s->pipe_size, s->rw_ti[cpu]); | ||
176 | } | ||
177 | |||
178 | /* init controller of read/write threads */ | ||
179 | s->ctl_fd = rw_ctl_init((const char *)CTL_PATH); | ||
180 | |||
181 | return NULL; | ||
182 | |||
183 | error: | ||
184 | exit(EXIT_FAILURE); | ||
185 | } | ||
186 | |||
187 | static void *parse_args(int argc, char *argv[], struct agent_info *s) | ||
188 | { | ||
189 | int cmd; | ||
190 | unsigned long size; | ||
191 | |||
192 | while ((cmd = getopt(argc, argv, "hos:")) != -1) { | ||
193 | switch (cmd) { | ||
194 | /* stdout mode */ | ||
195 | case 'o': | ||
196 | s->use_stdout = true; | ||
197 | break; | ||
198 | /* size of pipe */ | ||
199 | case 's': | ||
200 | size = parse_size(optarg); | ||
201 | if (size == 0) | ||
202 | goto error; | ||
203 | s->pipe_size = size; | ||
204 | break; | ||
205 | case 'h': | ||
206 | default: | ||
207 | usage(argv[0]); | ||
208 | goto error; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | agent_info_init(s); | ||
213 | |||
214 | return NULL; | ||
215 | |||
216 | error: | ||
217 | exit(EXIT_FAILURE); | ||
218 | } | ||
219 | |||
220 | static void agent_main_loop(struct agent_info *s) | ||
221 | { | ||
222 | int cpu; | ||
223 | pthread_t rw_thread_per_cpu[MAX_CPUS]; | ||
224 | |||
225 | /* Start all read/write threads */ | ||
226 | for (cpu = 0; cpu < s->cpus; cpu++) | ||
227 | rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]); | ||
228 | |||
229 | rw_ctl_loop(s->ctl_fd); | ||
230 | |||
231 | /* Finish all read/write threads */ | ||
232 | for (cpu = 0; cpu < s->cpus; cpu++) { | ||
233 | int ret; | ||
234 | |||
235 | ret = pthread_join(rw_thread_per_cpu[cpu], NULL); | ||
236 | if (ret != 0) { | ||
237 | pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu); | ||
238 | exit(EXIT_FAILURE); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static void agent_info_free(struct agent_info *s) | ||
244 | { | ||
245 | int i; | ||
246 | |||
247 | close(s->ctl_fd); | ||
248 | for (i = 0; i < s->cpus; i++) { | ||
249 | close(s->rw_ti[i]->in_fd); | ||
250 | close(s->rw_ti[i]->out_fd); | ||
251 | close(s->rw_ti[i]->read_pipe); | ||
252 | close(s->rw_ti[i]->write_pipe); | ||
253 | free(s->rw_ti[i]); | ||
254 | } | ||
255 | free(s); | ||
256 | } | ||
257 | |||
258 | int main(int argc, char *argv[]) | ||
259 | { | ||
260 | struct agent_info *s = NULL; | ||
261 | |||
262 | s = agent_info_new(); | ||
263 | parse_args(argc, argv, s); | ||
264 | |||
265 | agent_main_loop(s); | ||
266 | |||
267 | agent_info_free(s); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
diff --git a/tools/virtio/virtio-trace/trace-agent.h b/tools/virtio/virtio-trace/trace-agent.h new file mode 100644 index 000000000000..8de79bfeaa73 --- /dev/null +++ b/tools/virtio/virtio-trace/trace-agent.h | |||
@@ -0,0 +1,75 @@ | |||
1 | #ifndef __TRACE_AGENT_H__ | ||
2 | #define __TRACE_AGENT_H__ | ||
3 | #include <pthread.h> | ||
4 | #include <stdbool.h> | ||
5 | |||
6 | #define MAX_CPUS 256 | ||
7 | #define PIPE_INIT (1024*1024) | ||
8 | |||
9 | /* | ||
10 | * agent_info - structure managing total information of guest agent | ||
11 | * @pipe_size: size of pipe (default 1MB) | ||
12 | * @use_stdout: set to true when o option is added (default false) | ||
13 | * @cpus: total number of CPUs | ||
14 | * @ctl_fd: fd of control path, /dev/virtio-ports/agent-ctl-path | ||
15 | * @rw_ti: structure managing information of read/write threads | ||
16 | */ | ||
17 | struct agent_info { | ||
18 | unsigned long pipe_size; | ||
19 | bool use_stdout; | ||
20 | int cpus; | ||
21 | int ctl_fd; | ||
22 | struct rw_thread_info *rw_ti[MAX_CPUS]; | ||
23 | }; | ||
24 | |||
25 | /* | ||
26 | * rw_thread_info - structure managing a read/write thread a cpu | ||
27 | * @cpu_num: cpu number operating this read/write thread | ||
28 | * @in_fd: fd of reading trace data path in cpu_num | ||
29 | * @out_fd: fd of writing trace data path in cpu_num | ||
30 | * @read_pipe: fd of read pipe | ||
31 | * @write_pipe: fd of write pipe | ||
32 | * @pipe_size: size of pipe (default 1MB) | ||
33 | */ | ||
34 | struct rw_thread_info { | ||
35 | int cpu_num; | ||
36 | int in_fd; | ||
37 | int out_fd; | ||
38 | int read_pipe; | ||
39 | int write_pipe; | ||
40 | unsigned long pipe_size; | ||
41 | }; | ||
42 | |||
43 | /* use for stopping rw threads */ | ||
44 | extern bool global_sig_receive; | ||
45 | |||
46 | /* use for notification */ | ||
47 | extern bool global_run_operation; | ||
48 | extern pthread_mutex_t mutex_notify; | ||
49 | extern pthread_cond_t cond_wakeup; | ||
50 | |||
51 | /* for controller of read/write threads */ | ||
52 | extern int rw_ctl_init(const char *ctl_path); | ||
53 | extern void *rw_ctl_loop(int ctl_fd); | ||
54 | |||
55 | /* for trace read/write thread */ | ||
56 | extern void *rw_thread_info_new(void); | ||
57 | extern void *rw_thread_init(int cpu, const char *in_path, const char *out_path, | ||
58 | bool stdout_flag, unsigned long pipe_size, | ||
59 | struct rw_thread_info *rw_ti); | ||
60 | extern pthread_t rw_thread_run(struct rw_thread_info *rw_ti); | ||
61 | |||
62 | static inline void *zalloc(size_t size) | ||
63 | { | ||
64 | return calloc(1, size); | ||
65 | } | ||
66 | |||
67 | #define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__) | ||
68 | #define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__) | ||
69 | #ifdef DEBUG | ||
70 | #define pr_debug(format, ...) fprintf(stderr, format, ## __VA_ARGS__) | ||
71 | #else | ||
72 | #define pr_debug(format, ...) do {} while (0) | ||
73 | #endif | ||
74 | |||
75 | #endif /*__TRACE_AGENT_H__*/ | ||
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index f576971f6556..b76edf2f8333 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c | |||
@@ -34,8 +34,8 @@ | |||
34 | #include <sys/fcntl.h> | 34 | #include <sys/fcntl.h> |
35 | #include <sys/mount.h> | 35 | #include <sys/mount.h> |
36 | #include <sys/statfs.h> | 36 | #include <sys/statfs.h> |
37 | #include "../../include/linux/magic.h" | 37 | #include "../../include/uapi/linux/magic.h" |
38 | #include "../../include/linux/kernel-page-flags.h" | 38 | #include "../../include/uapi/linux/kernel-page-flags.h" |
39 | 39 | ||
40 | 40 | ||
41 | #ifndef MAX_PATH | 41 | #ifndef MAX_PATH |