diff options
| author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-05-04 11:27:05 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2010-05-04 11:29:05 -0400 |
| commit | 5306293c9cd2caf41849cc909281bda628bb989e (patch) | |
| tree | 3be4e8231e2772c8a43ddbef5c6a72c20b3054bb /tools | |
| parent | dbd65a7e44fff4741a0b2c84bd6bace85d22c242 (diff) | |
| parent | 66f41d4c5c8a5deed66fdcc84509376c9a0bf9d8 (diff) | |
Merge commit 'v2.6.34-rc6'
Conflicts:
fs/nfsd/nfs4callback.c
Diffstat (limited to 'tools')
31 files changed, 522 insertions, 114 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index bdd3b7ecad0a..bd498d496952 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile | |||
| @@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT)) | |||
| 24 | DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) | 24 | DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) |
| 25 | DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) | 25 | DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) |
| 26 | 26 | ||
| 27 | # Make the path relative to DESTDIR, not prefix | ||
| 28 | ifndef DESTDIR | ||
| 27 | prefix?=$(HOME) | 29 | prefix?=$(HOME) |
| 30 | endif | ||
| 28 | bindir?=$(prefix)/bin | 31 | bindir?=$(prefix)/bin |
| 29 | htmldir?=$(prefix)/share/doc/perf-doc | 32 | htmldir?=$(prefix)/share/doc/perf-doc |
| 30 | pdfdir?=$(prefix)/share/doc/perf-doc | 33 | pdfdir?=$(prefix)/share/doc/perf-doc |
| @@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man | |||
| 32 | man1dir=$(mandir)/man1 | 35 | man1dir=$(mandir)/man1 |
| 33 | man5dir=$(mandir)/man5 | 36 | man5dir=$(mandir)/man5 |
| 34 | man7dir=$(mandir)/man7 | 37 | man7dir=$(mandir)/man7 |
| 35 | # DESTDIR= | ||
| 36 | 38 | ||
| 37 | ASCIIDOC=asciidoc | 39 | ASCIIDOC=asciidoc |
| 38 | ASCIIDOC_EXTRA = --unsafe | 40 | ASCIIDOC_EXTRA = --unsafe |
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt new file mode 100644 index 000000000000..b317102138c8 --- /dev/null +++ b/tools/perf/Documentation/perf-lock.txt | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | perf-lock(1) | ||
| 2 | ============ | ||
| 3 | |||
| 4 | NAME | ||
| 5 | ---- | ||
| 6 | perf-lock - Analyze lock events | ||
| 7 | |||
| 8 | SYNOPSIS | ||
| 9 | -------- | ||
| 10 | [verse] | ||
| 11 | 'perf lock' {record|report|trace} | ||
| 12 | |||
| 13 | DESCRIPTION | ||
| 14 | ----------- | ||
| 15 | You can analyze various lock behaviours | ||
| 16 | and statistics with this 'perf lock' command. | ||
| 17 | |||
| 18 | 'perf lock record <command>' records lock events | ||
| 19 | between start and end <command>. And this command | ||
| 20 | produces the file "perf.data" which contains tracing | ||
| 21 | results of lock events. | ||
| 22 | |||
| 23 | 'perf lock trace' shows raw lock events. | ||
| 24 | |||
| 25 | 'perf lock report' reports statistical data. | ||
| 26 | |||
| 27 | SEE ALSO | ||
| 28 | -------- | ||
| 29 | linkperf:perf[1] | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2d537382c686..bc0f670a8338 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -200,7 +200,7 @@ endif | |||
| 200 | 200 | ||
| 201 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 201 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
| 202 | EXTLIBS = -lpthread -lrt -lelf -lm | 202 | EXTLIBS = -lpthread -lrt -lelf -lm |
| 203 | ALL_CFLAGS = $(CFLAGS) | 203 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 |
| 204 | ALL_LDFLAGS = $(LDFLAGS) | 204 | ALL_LDFLAGS = $(LDFLAGS) |
| 205 | STRIP ?= strip | 205 | STRIP ?= strip |
| 206 | 206 | ||
| @@ -216,7 +216,10 @@ STRIP ?= strip | |||
| 216 | # runtime figures out where they are based on the path to the executable. | 216 | # runtime figures out where they are based on the path to the executable. |
| 217 | # This can help installing the suite in a relocatable way. | 217 | # This can help installing the suite in a relocatable way. |
| 218 | 218 | ||
| 219 | # Make the path relative to DESTDIR, not to prefix | ||
| 220 | ifndef DESTDIR | ||
| 219 | prefix = $(HOME) | 221 | prefix = $(HOME) |
| 222 | endif | ||
| 220 | bindir_relative = bin | 223 | bindir_relative = bin |
| 221 | bindir = $(prefix)/$(bindir_relative) | 224 | bindir = $(prefix)/$(bindir_relative) |
| 222 | mandir = share/man | 225 | mandir = share/man |
| @@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc | |||
| 233 | ETC_PERFCONFIG = etc/perfconfig | 236 | ETC_PERFCONFIG = etc/perfconfig |
| 234 | endif | 237 | endif |
| 235 | lib = lib | 238 | lib = lib |
| 236 | # DESTDIR= | ||
| 237 | 239 | ||
| 238 | export prefix bindir sharedir sysconfdir | 240 | export prefix bindir sharedir sysconfdir |
| 239 | 241 | ||
| @@ -387,6 +389,7 @@ LIB_H += util/thread.h | |||
| 387 | LIB_H += util/trace-event.h | 389 | LIB_H += util/trace-event.h |
| 388 | LIB_H += util/probe-finder.h | 390 | LIB_H += util/probe-finder.h |
| 389 | LIB_H += util/probe-event.h | 391 | LIB_H += util/probe-event.h |
| 392 | LIB_H += util/cpumap.h | ||
| 390 | 393 | ||
| 391 | LIB_OBJS += util/abspath.o | 394 | LIB_OBJS += util/abspath.o |
| 392 | LIB_OBJS += util/alias.o | 395 | LIB_OBJS += util/alias.o |
| @@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o | |||
| 433 | LIB_OBJS += util/hist.o | 436 | LIB_OBJS += util/hist.o |
| 434 | LIB_OBJS += util/probe-event.o | 437 | LIB_OBJS += util/probe-event.o |
| 435 | LIB_OBJS += util/util.o | 438 | LIB_OBJS += util/util.o |
| 439 | LIB_OBJS += util/cpumap.o | ||
| 436 | 440 | ||
| 437 | BUILTIN_OBJS += builtin-annotate.o | 441 | BUILTIN_OBJS += builtin-annotate.o |
| 438 | 442 | ||
| @@ -488,19 +492,19 @@ ifeq ($(uname_S),Darwin) | |||
| 488 | PTHREAD_LIBS = | 492 | PTHREAD_LIBS = |
| 489 | endif | 493 | endif |
| 490 | 494 | ||
| 491 | ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 495 | ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
| 492 | ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 496 | ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
| 493 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | 497 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); |
| 494 | endif | 498 | endif |
| 495 | 499 | ||
| 496 | ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 500 | ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
| 497 | BASIC_CFLAGS += -DLIBELF_NO_MMAP | 501 | BASIC_CFLAGS += -DLIBELF_NO_MMAP |
| 498 | endif | 502 | endif |
| 499 | else | 503 | else |
| 500 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); | 504 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); |
| 501 | endif | 505 | endif |
| 502 | 506 | ||
| 503 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 507 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
| 504 | msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); | 508 | msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); |
| 505 | BASIC_CFLAGS += -DNO_DWARF_SUPPORT | 509 | BASIC_CFLAGS += -DNO_DWARF_SUPPORT |
| 506 | else | 510 | else |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5ec5de995872..6ad7148451c5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
| 116 | return 0; | 116 | return 0; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); | 119 | he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit); |
| 120 | if (he == NULL) | 120 | if (he == NULL) |
| 121 | return -ENOMEM; | 121 | return -ENOMEM; |
| 122 | 122 | ||
| @@ -564,8 +564,8 @@ static int __cmd_annotate(void) | |||
| 564 | if (verbose > 2) | 564 | if (verbose > 2) |
| 565 | dsos__fprintf(stdout); | 565 | dsos__fprintf(stdout); |
| 566 | 566 | ||
| 567 | perf_session__collapse_resort(session); | 567 | perf_session__collapse_resort(&session->hists); |
| 568 | perf_session__output_resort(session, session->event_total[0]); | 568 | perf_session__output_resort(&session->hists, session->event_total[0]); |
| 569 | perf_session__find_annotations(session); | 569 | perf_session__find_annotations(session); |
| 570 | out_delete: | 570 | out_delete: |
| 571 | perf_session__delete(session); | 571 | perf_session__delete(session); |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 18b3f505f9db..1ea15d8aeed1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -26,7 +26,8 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
| 26 | struct addr_location *al, u64 count) | 26 | struct addr_location *al, u64 count) |
| 27 | { | 27 | { |
| 28 | bool hit; | 28 | bool hit; |
| 29 | struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, | 29 | struct hist_entry *he = __perf_session__add_hist_entry(&self->hists, |
| 30 | al, NULL, | ||
| 30 | count, &hit); | 31 | count, &hit); |
| 31 | if (he == NULL) | 32 | if (he == NULL) |
| 32 | return -ENOMEM; | 33 | return -ENOMEM; |
| @@ -114,7 +115,7 @@ static void perf_session__resort_hist_entries(struct perf_session *self) | |||
| 114 | 115 | ||
| 115 | static void perf_session__set_hist_entries_positions(struct perf_session *self) | 116 | static void perf_session__set_hist_entries_positions(struct perf_session *self) |
| 116 | { | 117 | { |
| 117 | perf_session__output_resort(self, self->events_stats.total); | 118 | perf_session__output_resort(&self->hists, self->events_stats.total); |
| 118 | perf_session__resort_hist_entries(self); | 119 | perf_session__resort_hist_entries(self); |
| 119 | } | 120 | } |
| 120 | 121 | ||
| @@ -166,13 +167,15 @@ static int __cmd_diff(void) | |||
| 166 | goto out_delete; | 167 | goto out_delete; |
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | perf_session__output_resort(session[1], session[1]->events_stats.total); | 170 | perf_session__output_resort(&session[1]->hists, |
| 171 | session[1]->events_stats.total); | ||
| 170 | if (show_displacement) | 172 | if (show_displacement) |
| 171 | perf_session__set_hist_entries_positions(session[0]); | 173 | perf_session__set_hist_entries_positions(session[0]); |
| 172 | 174 | ||
| 173 | perf_session__match_hists(session[0], session[1]); | 175 | perf_session__match_hists(session[0], session[1]); |
| 174 | perf_session__fprintf_hists(session[1], session[0], | 176 | perf_session__fprintf_hists(&session[1]->hists, session[0], |
| 175 | show_displacement, stdout); | 177 | show_displacement, stdout, |
| 178 | session[1]->events_stats.total); | ||
| 176 | out_delete: | 179 | out_delete: |
| 177 | for (i = 0; i < 2; ++i) | 180 | for (i = 0; i < 2; ++i) |
| 178 | perf_session__delete(session[i]); | 181 | perf_session__delete(session[i]); |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index fb9ab2ad3f92..e12c844df1e2 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
| @@ -460,6 +460,150 @@ process_raw_event(void *data, int cpu, | |||
| 460 | process_lock_release_event(data, event, cpu, timestamp, thread); | 460 | process_lock_release_event(data, event, cpu, timestamp, thread); |
| 461 | } | 461 | } |
| 462 | 462 | ||
| 463 | struct raw_event_queue { | ||
| 464 | u64 timestamp; | ||
| 465 | int cpu; | ||
| 466 | void *data; | ||
| 467 | struct thread *thread; | ||
| 468 | struct list_head list; | ||
| 469 | }; | ||
| 470 | |||
| 471 | static LIST_HEAD(raw_event_head); | ||
| 472 | |||
| 473 | #define FLUSH_PERIOD (5 * NSEC_PER_SEC) | ||
| 474 | |||
| 475 | static u64 flush_limit = ULLONG_MAX; | ||
| 476 | static u64 last_flush = 0; | ||
| 477 | struct raw_event_queue *last_inserted; | ||
| 478 | |||
| 479 | static void flush_raw_event_queue(u64 limit) | ||
| 480 | { | ||
| 481 | struct raw_event_queue *tmp, *iter; | ||
| 482 | |||
| 483 | list_for_each_entry_safe(iter, tmp, &raw_event_head, list) { | ||
| 484 | if (iter->timestamp > limit) | ||
| 485 | return; | ||
| 486 | |||
| 487 | if (iter == last_inserted) | ||
| 488 | last_inserted = NULL; | ||
| 489 | |||
| 490 | process_raw_event(iter->data, iter->cpu, iter->timestamp, | ||
| 491 | iter->thread); | ||
| 492 | |||
| 493 | last_flush = iter->timestamp; | ||
| 494 | list_del(&iter->list); | ||
| 495 | free(iter->data); | ||
| 496 | free(iter); | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | static void __queue_raw_event_end(struct raw_event_queue *new) | ||
| 501 | { | ||
| 502 | struct raw_event_queue *iter; | ||
| 503 | |||
| 504 | list_for_each_entry_reverse(iter, &raw_event_head, list) { | ||
| 505 | if (iter->timestamp < new->timestamp) { | ||
| 506 | list_add(&new->list, &iter->list); | ||
| 507 | return; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | list_add(&new->list, &raw_event_head); | ||
| 512 | } | ||
| 513 | |||
| 514 | static void __queue_raw_event_before(struct raw_event_queue *new, | ||
| 515 | struct raw_event_queue *iter) | ||
| 516 | { | ||
| 517 | list_for_each_entry_continue_reverse(iter, &raw_event_head, list) { | ||
| 518 | if (iter->timestamp < new->timestamp) { | ||
| 519 | list_add(&new->list, &iter->list); | ||
| 520 | return; | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | list_add(&new->list, &raw_event_head); | ||
| 525 | } | ||
| 526 | |||
| 527 | static void __queue_raw_event_after(struct raw_event_queue *new, | ||
| 528 | struct raw_event_queue *iter) | ||
| 529 | { | ||
| 530 | list_for_each_entry_continue(iter, &raw_event_head, list) { | ||
| 531 | if (iter->timestamp > new->timestamp) { | ||
| 532 | list_add_tail(&new->list, &iter->list); | ||
| 533 | return; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | list_add_tail(&new->list, &raw_event_head); | ||
| 537 | } | ||
| 538 | |||
| 539 | /* The queue is ordered by time */ | ||
| 540 | static void __queue_raw_event(struct raw_event_queue *new) | ||
| 541 | { | ||
| 542 | if (!last_inserted) { | ||
| 543 | __queue_raw_event_end(new); | ||
| 544 | return; | ||
| 545 | } | ||
| 546 | |||
| 547 | /* | ||
| 548 | * Most of the time the current event has a timestamp | ||
| 549 | * very close to the last event inserted, unless we just switched | ||
| 550 | * to another event buffer. Having a sorting based on a list and | ||
| 551 | * on the last inserted event that is close to the current one is | ||
| 552 | * probably more efficient than an rbtree based sorting. | ||
| 553 | */ | ||
| 554 | if (last_inserted->timestamp >= new->timestamp) | ||
| 555 | __queue_raw_event_before(new, last_inserted); | ||
| 556 | else | ||
| 557 | __queue_raw_event_after(new, last_inserted); | ||
| 558 | } | ||
| 559 | |||
| 560 | static void queue_raw_event(void *data, int raw_size, int cpu, | ||
| 561 | u64 timestamp, struct thread *thread) | ||
| 562 | { | ||
| 563 | struct raw_event_queue *new; | ||
| 564 | |||
| 565 | if (flush_limit == ULLONG_MAX) | ||
| 566 | flush_limit = timestamp + FLUSH_PERIOD; | ||
| 567 | |||
| 568 | if (timestamp < last_flush) { | ||
| 569 | printf("Warning: Timestamp below last timeslice flush\n"); | ||
| 570 | return; | ||
| 571 | } | ||
| 572 | |||
| 573 | new = malloc(sizeof(*new)); | ||
| 574 | if (!new) | ||
| 575 | die("Not enough memory\n"); | ||
| 576 | |||
| 577 | new->timestamp = timestamp; | ||
| 578 | new->cpu = cpu; | ||
| 579 | new->thread = thread; | ||
| 580 | |||
| 581 | new->data = malloc(raw_size); | ||
| 582 | if (!new->data) | ||
| 583 | die("Not enough memory\n"); | ||
| 584 | |||
| 585 | memcpy(new->data, data, raw_size); | ||
| 586 | |||
| 587 | __queue_raw_event(new); | ||
| 588 | last_inserted = new; | ||
| 589 | |||
| 590 | /* | ||
| 591 | * We want to have a slice of events covering 2 * FLUSH_PERIOD | ||
| 592 | * If FLUSH_PERIOD is big enough, it ensures every events that occured | ||
| 593 | * in the first half of the timeslice have all been buffered and there | ||
| 594 | * are none remaining (we need that because of the weakly ordered | ||
| 595 | * event recording we have). Then once we reach the 2 * FLUSH_PERIOD | ||
| 596 | * timeslice, we flush the first half to be gentle with the memory | ||
| 597 | * (the second half can still get new events in the middle, so wait | ||
| 598 | * another period to flush it) | ||
| 599 | */ | ||
| 600 | if (new->timestamp > flush_limit && | ||
| 601 | new->timestamp - flush_limit > FLUSH_PERIOD) { | ||
| 602 | flush_limit += FLUSH_PERIOD; | ||
| 603 | flush_raw_event_queue(flush_limit); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 463 | static int process_sample_event(event_t *event, struct perf_session *session) | 607 | static int process_sample_event(event_t *event, struct perf_session *session) |
| 464 | { | 608 | { |
| 465 | struct thread *thread; | 609 | struct thread *thread; |
| @@ -480,7 +624,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 480 | if (profile_cpu != -1 && profile_cpu != (int) data.cpu) | 624 | if (profile_cpu != -1 && profile_cpu != (int) data.cpu) |
| 481 | return 0; | 625 | return 0; |
| 482 | 626 | ||
| 483 | process_raw_event(data.raw_data, data.cpu, data.time, thread); | 627 | queue_raw_event(data.raw_data, data.raw_size, data.cpu, data.time, thread); |
| 484 | 628 | ||
| 485 | return 0; | 629 | return 0; |
| 486 | } | 630 | } |
| @@ -576,6 +720,7 @@ static void __cmd_report(void) | |||
| 576 | setup_pager(); | 720 | setup_pager(); |
| 577 | select_key(); | 721 | select_key(); |
| 578 | read_events(); | 722 | read_events(); |
| 723 | flush_raw_event_queue(ULLONG_MAX); | ||
| 579 | sort_result(); | 724 | sort_result(); |
| 580 | print_result(); | 725 | print_result(); |
| 581 | } | 726 | } |
| @@ -608,7 +753,6 @@ static const char *record_args[] = { | |||
| 608 | "record", | 753 | "record", |
| 609 | "-a", | 754 | "-a", |
| 610 | "-R", | 755 | "-R", |
| 611 | "-M", | ||
| 612 | "-f", | 756 | "-f", |
| 613 | "-m", "1024", | 757 | "-m", "1024", |
| 614 | "-c", "1", | 758 | "-c", "1", |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c30a33592340..152d6c9b1fa4 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -47,7 +47,6 @@ | |||
| 47 | #include "util/probe-event.h" | 47 | #include "util/probe-event.h" |
| 48 | 48 | ||
| 49 | #define MAX_PATH_LEN 256 | 49 | #define MAX_PATH_LEN 256 |
| 50 | #define MAX_PROBES 128 | ||
| 51 | 50 | ||
| 52 | /* Session management structure */ | 51 | /* Session management structure */ |
| 53 | static struct { | 52 | static struct { |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 771533ced6a8..3b8b6387c47c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "util/debug.h" | 22 | #include "util/debug.h" |
| 23 | #include "util/session.h" | 23 | #include "util/session.h" |
| 24 | #include "util/symbol.h" | 24 | #include "util/symbol.h" |
| 25 | #include "util/cpumap.h" | ||
| 25 | 26 | ||
| 26 | #include <unistd.h> | 27 | #include <unistd.h> |
| 27 | #include <sched.h> | 28 | #include <sched.h> |
| @@ -244,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
| 244 | 245 | ||
| 245 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 246 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
| 246 | 247 | ||
| 248 | if (nr_counters > 1) | ||
| 249 | attr->sample_type |= PERF_SAMPLE_ID; | ||
| 250 | |||
| 247 | if (freq) { | 251 | if (freq) { |
| 248 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 252 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
| 249 | attr->freq = 1; | 253 | attr->freq = 1; |
| @@ -391,6 +395,9 @@ static int process_buildids(void) | |||
| 391 | { | 395 | { |
| 392 | u64 size = lseek(output, 0, SEEK_CUR); | 396 | u64 size = lseek(output, 0, SEEK_CUR); |
| 393 | 397 | ||
| 398 | if (size == 0) | ||
| 399 | return 0; | ||
| 400 | |||
| 394 | session->fd = output; | 401 | session->fd = output; |
| 395 | return __perf_session__process_events(session, post_processing_offset, | 402 | return __perf_session__process_events(session, post_processing_offset, |
| 396 | size - post_processing_offset, | 403 | size - post_processing_offset, |
| @@ -418,9 +425,6 @@ static int __cmd_record(int argc, const char **argv) | |||
| 418 | char buf; | 425 | char buf; |
| 419 | 426 | ||
| 420 | page_size = sysconf(_SC_PAGE_SIZE); | 427 | page_size = sysconf(_SC_PAGE_SIZE); |
| 421 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
| 422 | assert(nr_cpus <= MAX_NR_CPUS); | ||
| 423 | assert(nr_cpus >= 0); | ||
| 424 | 428 | ||
| 425 | atexit(sig_atexit); | 429 | atexit(sig_atexit); |
| 426 | signal(SIGCHLD, sig_handler); | 430 | signal(SIGCHLD, sig_handler); |
| @@ -544,8 +548,9 @@ static int __cmd_record(int argc, const char **argv) | |||
| 544 | if ((!system_wide && !inherit) || profile_cpu != -1) { | 548 | if ((!system_wide && !inherit) || profile_cpu != -1) { |
| 545 | open_counters(profile_cpu, target_pid); | 549 | open_counters(profile_cpu, target_pid); |
| 546 | } else { | 550 | } else { |
| 551 | nr_cpus = read_cpu_map(); | ||
| 547 | for (i = 0; i < nr_cpus; i++) | 552 | for (i = 0; i < nr_cpus; i++) |
| 548 | open_counters(i, target_pid); | 553 | open_counters(cpumap[i], target_pid); |
| 549 | } | 554 | } |
| 550 | 555 | ||
| 551 | if (file_new) { | 556 | if (file_new) { |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cfc655d40bb7..f815de25d0fc 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -45,28 +45,71 @@ static char *pretty_printing_style = default_pretty_printing_style; | |||
| 45 | 45 | ||
| 46 | static char callchain_default_opt[] = "fractal,0.5"; | 46 | static char callchain_default_opt[] = "fractal,0.5"; |
| 47 | 47 | ||
| 48 | static struct event_stat_id *get_stats(struct perf_session *self, | ||
| 49 | u64 event_stream, u32 type, u64 config) | ||
| 50 | { | ||
| 51 | struct rb_node **p = &self->stats_by_id.rb_node; | ||
| 52 | struct rb_node *parent = NULL; | ||
| 53 | struct event_stat_id *iter, *new; | ||
| 54 | |||
| 55 | while (*p != NULL) { | ||
| 56 | parent = *p; | ||
| 57 | iter = rb_entry(parent, struct event_stat_id, rb_node); | ||
| 58 | if (iter->config == config) | ||
| 59 | return iter; | ||
| 60 | |||
| 61 | |||
| 62 | if (config > iter->config) | ||
| 63 | p = &(*p)->rb_right; | ||
| 64 | else | ||
| 65 | p = &(*p)->rb_left; | ||
| 66 | } | ||
| 67 | |||
| 68 | new = malloc(sizeof(struct event_stat_id)); | ||
| 69 | if (new == NULL) | ||
| 70 | return NULL; | ||
| 71 | memset(new, 0, sizeof(struct event_stat_id)); | ||
| 72 | new->event_stream = event_stream; | ||
| 73 | new->config = config; | ||
| 74 | new->type = type; | ||
| 75 | rb_link_node(&new->rb_node, parent, p); | ||
| 76 | rb_insert_color(&new->rb_node, &self->stats_by_id); | ||
| 77 | return new; | ||
| 78 | } | ||
| 79 | |||
| 48 | static int perf_session__add_hist_entry(struct perf_session *self, | 80 | static int perf_session__add_hist_entry(struct perf_session *self, |
| 49 | struct addr_location *al, | 81 | struct addr_location *al, |
| 50 | struct ip_callchain *chain, u64 count) | 82 | struct sample_data *data) |
| 51 | { | 83 | { |
| 52 | struct symbol **syms = NULL, *parent = NULL; | 84 | struct symbol **syms = NULL, *parent = NULL; |
| 53 | bool hit; | 85 | bool hit; |
| 54 | struct hist_entry *he; | 86 | struct hist_entry *he; |
| 87 | struct event_stat_id *stats; | ||
| 88 | struct perf_event_attr *attr; | ||
| 55 | 89 | ||
| 56 | if ((sort__has_parent || symbol_conf.use_callchain) && chain) | 90 | if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) |
| 57 | syms = perf_session__resolve_callchain(self, al->thread, | 91 | syms = perf_session__resolve_callchain(self, al->thread, |
| 58 | chain, &parent); | 92 | data->callchain, &parent); |
| 59 | he = __perf_session__add_hist_entry(self, al, parent, count, &hit); | 93 | |
| 94 | attr = perf_header__find_attr(data->id, &self->header); | ||
| 95 | if (attr) | ||
| 96 | stats = get_stats(self, data->id, attr->type, attr->config); | ||
| 97 | else | ||
| 98 | stats = get_stats(self, data->id, 0, 0); | ||
| 99 | if (stats == NULL) | ||
| 100 | return -ENOMEM; | ||
| 101 | he = __perf_session__add_hist_entry(&stats->hists, al, parent, | ||
| 102 | data->period, &hit); | ||
| 60 | if (he == NULL) | 103 | if (he == NULL) |
| 61 | return -ENOMEM; | 104 | return -ENOMEM; |
| 62 | 105 | ||
| 63 | if (hit) | 106 | if (hit) |
| 64 | he->count += count; | 107 | he->count += data->period; |
| 65 | 108 | ||
| 66 | if (symbol_conf.use_callchain) { | 109 | if (symbol_conf.use_callchain) { |
| 67 | if (!hit) | 110 | if (!hit) |
| 68 | callchain_init(&he->callchain); | 111 | callchain_init(&he->callchain); |
| 69 | append_chain(&he->callchain, chain, syms); | 112 | append_chain(&he->callchain, data->callchain, syms); |
| 70 | free(syms); | 113 | free(syms); |
| 71 | } | 114 | } |
| 72 | 115 | ||
| @@ -86,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
| 86 | return 0; | 129 | return 0; |
| 87 | } | 130 | } |
| 88 | 131 | ||
| 132 | static int add_event_total(struct perf_session *session, | ||
| 133 | struct sample_data *data, | ||
| 134 | struct perf_event_attr *attr) | ||
| 135 | { | ||
| 136 | struct event_stat_id *stats; | ||
| 137 | |||
| 138 | if (attr) | ||
| 139 | stats = get_stats(session, data->id, attr->type, attr->config); | ||
| 140 | else | ||
| 141 | stats = get_stats(session, data->id, 0, 0); | ||
| 142 | |||
| 143 | if (!stats) | ||
| 144 | return -ENOMEM; | ||
| 145 | |||
| 146 | stats->stats.total += data->period; | ||
| 147 | session->events_stats.total += data->period; | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 89 | static int process_sample_event(event_t *event, struct perf_session *session) | 151 | static int process_sample_event(event_t *event, struct perf_session *session) |
| 90 | { | 152 | { |
| 91 | struct sample_data data = { .period = 1, }; | 153 | struct sample_data data = { .period = 1, }; |
| 92 | struct addr_location al; | 154 | struct addr_location al; |
| 155 | struct perf_event_attr *attr; | ||
| 93 | 156 | ||
| 94 | event__parse_sample(event, session->sample_type, &data); | 157 | event__parse_sample(event, session->sample_type, &data); |
| 95 | 158 | ||
| @@ -123,12 +186,18 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 123 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 186 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
| 124 | return 0; | 187 | return 0; |
| 125 | 188 | ||
| 126 | if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { | 189 | if (perf_session__add_hist_entry(session, &al, &data)) { |
| 127 | pr_debug("problem incrementing symbol count, skipping event\n"); | 190 | pr_debug("problem incrementing symbol count, skipping event\n"); |
| 128 | return -1; | 191 | return -1; |
| 129 | } | 192 | } |
| 130 | 193 | ||
| 131 | session->events_stats.total += data.period; | 194 | attr = perf_header__find_attr(data.id, &session->header); |
| 195 | |||
| 196 | if (add_event_total(session, &data, attr)) { | ||
| 197 | pr_debug("problem adding event count\n"); | ||
| 198 | return -1; | ||
| 199 | } | ||
| 200 | |||
| 132 | return 0; | 201 | return 0; |
| 133 | } | 202 | } |
| 134 | 203 | ||
| @@ -197,6 +266,7 @@ static int __cmd_report(void) | |||
| 197 | { | 266 | { |
| 198 | int ret = -EINVAL; | 267 | int ret = -EINVAL; |
| 199 | struct perf_session *session; | 268 | struct perf_session *session; |
| 269 | struct rb_node *next; | ||
| 200 | 270 | ||
| 201 | session = perf_session__new(input_name, O_RDONLY, force); | 271 | session = perf_session__new(input_name, O_RDONLY, force); |
| 202 | if (session == NULL) | 272 | if (session == NULL) |
| @@ -224,10 +294,28 @@ static int __cmd_report(void) | |||
| 224 | if (verbose > 2) | 294 | if (verbose > 2) |
| 225 | dsos__fprintf(stdout); | 295 | dsos__fprintf(stdout); |
| 226 | 296 | ||
| 227 | perf_session__collapse_resort(session); | 297 | next = rb_first(&session->stats_by_id); |
| 228 | perf_session__output_resort(session, session->events_stats.total); | 298 | while (next) { |
| 229 | fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); | 299 | struct event_stat_id *stats; |
| 230 | perf_session__fprintf_hists(session, NULL, false, stdout); | 300 | |
| 301 | stats = rb_entry(next, struct event_stat_id, rb_node); | ||
| 302 | perf_session__collapse_resort(&stats->hists); | ||
| 303 | perf_session__output_resort(&stats->hists, stats->stats.total); | ||
| 304 | if (rb_first(&session->stats_by_id) == | ||
| 305 | rb_last(&session->stats_by_id)) | ||
| 306 | fprintf(stdout, "# Samples: %Ld\n#\n", | ||
| 307 | stats->stats.total); | ||
| 308 | else | ||
| 309 | fprintf(stdout, "# Samples: %Ld %s\n#\n", | ||
| 310 | stats->stats.total, | ||
| 311 | __event_name(stats->type, stats->config)); | ||
| 312 | |||
| 313 | perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, | ||
| 314 | stats->stats.total); | ||
| 315 | fprintf(stdout, "\n\n"); | ||
| 316 | next = rb_next(&stats->rb_node); | ||
| 317 | } | ||
| 318 | |||
| 231 | if (sort_order == default_sort_order && | 319 | if (sort_order == default_sort_order && |
| 232 | parent_pattern == default_parent_pattern) | 320 | parent_pattern == default_parent_pattern) |
| 233 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); | 321 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8c85d5aec41..95db31cff6fd 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include "util/event.h" | 45 | #include "util/event.h" |
| 46 | #include "util/debug.h" | 46 | #include "util/debug.h" |
| 47 | #include "util/header.h" | 47 | #include "util/header.h" |
| 48 | #include "util/cpumap.h" | ||
| 48 | 49 | ||
| 49 | #include <sys/prctl.h> | 50 | #include <sys/prctl.h> |
| 50 | #include <math.h> | 51 | #include <math.h> |
| @@ -151,7 +152,7 @@ static void create_perf_stat_counter(int counter, int pid) | |||
| 151 | unsigned int cpu; | 152 | unsigned int cpu; |
| 152 | 153 | ||
| 153 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 154 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 154 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); | 155 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0); |
| 155 | if (fd[cpu][counter] < 0 && verbose) | 156 | if (fd[cpu][counter] < 0 && verbose) |
| 156 | fprintf(stderr, ERR_PERF_OPEN, counter, | 157 | fprintf(stderr, ERR_PERF_OPEN, counter, |
| 157 | fd[cpu][counter], strerror(errno)); | 158 | fd[cpu][counter], strerror(errno)); |
| @@ -519,9 +520,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
| 519 | nr_counters = ARRAY_SIZE(default_attrs); | 520 | nr_counters = ARRAY_SIZE(default_attrs); |
| 520 | } | 521 | } |
| 521 | 522 | ||
| 522 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 523 | if (system_wide) |
| 523 | assert(nr_cpus <= MAX_NR_CPUS); | 524 | nr_cpus = read_cpu_map(); |
| 524 | assert((int)nr_cpus >= 0); | 525 | else |
| 526 | nr_cpus = 1; | ||
| 525 | 527 | ||
| 526 | /* | 528 | /* |
| 527 | * We dont want to block the signals - that would cause | 529 | * We dont want to block the signals - that would cause |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31f2e597800c..1f529321607e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/rbtree.h> | 28 | #include <linux/rbtree.h> |
| 29 | #include "util/parse-options.h" | 29 | #include "util/parse-options.h" |
| 30 | #include "util/parse-events.h" | 30 | #include "util/parse-events.h" |
| 31 | #include "util/cpumap.h" | ||
| 31 | 32 | ||
| 32 | #include "util/debug.h" | 33 | #include "util/debug.h" |
| 33 | 34 | ||
| @@ -454,7 +455,7 @@ static void print_sym_table(void) | |||
| 454 | struct sym_entry *syme, *n; | 455 | struct sym_entry *syme, *n; |
| 455 | struct rb_root tmp = RB_ROOT; | 456 | struct rb_root tmp = RB_ROOT; |
| 456 | struct rb_node *nd; | 457 | struct rb_node *nd; |
| 457 | int sym_width = 0, dso_width = 0, max_dso_width; | 458 | int sym_width = 0, dso_width = 0, dso_short_width = 0; |
| 458 | const int win_width = winsize.ws_col - 1; | 459 | const int win_width = winsize.ws_col - 1; |
| 459 | 460 | ||
| 460 | samples = userspace_samples = 0; | 461 | samples = userspace_samples = 0; |
| @@ -544,15 +545,20 @@ static void print_sym_table(void) | |||
| 544 | if (syme->map->dso->long_name_len > dso_width) | 545 | if (syme->map->dso->long_name_len > dso_width) |
| 545 | dso_width = syme->map->dso->long_name_len; | 546 | dso_width = syme->map->dso->long_name_len; |
| 546 | 547 | ||
| 548 | if (syme->map->dso->short_name_len > dso_short_width) | ||
| 549 | dso_short_width = syme->map->dso->short_name_len; | ||
| 550 | |||
| 547 | if (syme->name_len > sym_width) | 551 | if (syme->name_len > sym_width) |
| 548 | sym_width = syme->name_len; | 552 | sym_width = syme->name_len; |
| 549 | } | 553 | } |
| 550 | 554 | ||
| 551 | printed = 0; | 555 | printed = 0; |
| 552 | 556 | ||
| 553 | max_dso_width = winsize.ws_col - sym_width - 29; | 557 | if (sym_width + dso_width > winsize.ws_col - 29) { |
| 554 | if (dso_width > max_dso_width) | 558 | dso_width = dso_short_width; |
| 555 | dso_width = max_dso_width; | 559 | if (sym_width + dso_width > winsize.ws_col - 29) |
| 560 | sym_width = winsize.ws_col - dso_width - 29; | ||
| 561 | } | ||
| 556 | putchar('\n'); | 562 | putchar('\n'); |
| 557 | if (nr_counters == 1) | 563 | if (nr_counters == 1) |
| 558 | printf(" samples pcnt"); | 564 | printf(" samples pcnt"); |
| @@ -1123,7 +1129,7 @@ static void start_counter(int i, int counter) | |||
| 1123 | 1129 | ||
| 1124 | cpu = profile_cpu; | 1130 | cpu = profile_cpu; |
| 1125 | if (target_pid == -1 && profile_cpu == -1) | 1131 | if (target_pid == -1 && profile_cpu == -1) |
| 1126 | cpu = i; | 1132 | cpu = cpumap[i]; |
| 1127 | 1133 | ||
| 1128 | attr = attrs + counter; | 1134 | attr = attrs + counter; |
| 1129 | 1135 | ||
| @@ -1347,12 +1353,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
| 1347 | attrs[counter].sample_period = default_interval; | 1353 | attrs[counter].sample_period = default_interval; |
| 1348 | } | 1354 | } |
| 1349 | 1355 | ||
| 1350 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
| 1351 | assert(nr_cpus <= MAX_NR_CPUS); | ||
| 1352 | assert(nr_cpus >= 0); | ||
| 1353 | |||
| 1354 | if (target_pid != -1 || profile_cpu != -1) | 1356 | if (target_pid != -1 || profile_cpu != -1) |
| 1355 | nr_cpus = 1; | 1357 | nr_cpus = 1; |
| 1358 | else | ||
| 1359 | nr_cpus = read_cpu_map(); | ||
| 1356 | 1360 | ||
| 1357 | get_term_dimensions(&winsize); | 1361 | get_term_dimensions(&winsize); |
| 1358 | if (print_entries == 0) { | 1362 | if (print_entries == 0) { |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5db687fc13de..407041d20de0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -573,7 +573,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 573 | 573 | ||
| 574 | if (symbol__init() < 0) | 574 | if (symbol__init() < 0) |
| 575 | return -1; | 575 | return -1; |
| 576 | setup_pager(); | 576 | if (!script_name) |
| 577 | setup_pager(); | ||
| 577 | 578 | ||
| 578 | session = perf_session__new(input_name, O_RDONLY, 0); | 579 | session = perf_session__new(input_name, O_RDONLY, 0); |
| 579 | if (session == NULL) | 580 | if (session == NULL) |
| @@ -608,7 +609,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
| 608 | return -1; | 609 | return -1; |
| 609 | } | 610 | } |
| 610 | 611 | ||
| 611 | perf_header__read(&session->header, input); | ||
| 612 | err = scripting_ops->generate_script("perf-trace"); | 612 | err = scripting_ops->generate_script("perf-trace"); |
| 613 | goto out; | 613 | goto out; |
| 614 | } | 614 | } |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 9afcff2e3ae5..db6ee94d4a8e 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
| @@ -18,3 +18,4 @@ perf-top mainporcelain common | |||
| 18 | perf-trace mainporcelain common | 18 | perf-trace mainporcelain common |
| 19 | perf-probe mainporcelain common | 19 | perf-probe mainporcelain common |
| 20 | perf-kmem mainporcelain common | 20 | perf-kmem mainporcelain common |
| 21 | perf-lock mainporcelain common | ||
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh index 45fbe2f07b15..910468e6e01c 100644 --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh | |||
| @@ -9,8 +9,9 @@ fi | |||
| 9 | 9 | ||
| 10 | DEBUGDIR=~/.debug/ | 10 | DEBUGDIR=~/.debug/ |
| 11 | BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) | 11 | BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) |
| 12 | NOBUILDID=0000000000000000000000000000000000000000 | ||
| 12 | 13 | ||
| 13 | perf buildid-list -i $PERF_DATA --with-hits > $BUILDIDS | 14 | perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS |
| 14 | if [ ! -s $BUILDIDS ] ; then | 15 | if [ ! -s $BUILDIDS ] ; then |
| 15 | echo "perf archive: no build-ids found" | 16 | echo "perf archive: no build-ids found" |
| 16 | rm -f $BUILDIDS | 17 | rm -f $BUILDIDS |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 57cb107c1f13..cd32c200cdb3 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -445,7 +445,7 @@ int main(int argc, const char **argv) | |||
| 445 | 445 | ||
| 446 | /* | 446 | /* |
| 447 | * We use PATH to find perf commands, but we prepend some higher | 447 | * We use PATH to find perf commands, but we prepend some higher |
| 448 | * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH | 448 | * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH |
| 449 | * environment, and the $(perfexecdir) from the Makefile at build | 449 | * environment, and the $(perfexecdir) from the Makefile at build |
| 450 | * time. | 450 | * time. |
| 451 | */ | 451 | */ |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 75f941bfba9e..6fb379bc1d1f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -65,9 +65,7 @@ | |||
| 65 | * Use the __kuser_memory_barrier helper in the CPU helper page. See | 65 | * Use the __kuser_memory_barrier helper in the CPU helper page. See |
| 66 | * arch/arm/kernel/entry-armv.S in the kernel source for details. | 66 | * arch/arm/kernel/entry-armv.S in the kernel source for details. |
| 67 | */ | 67 | */ |
| 68 | #define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \ | 68 | #define rmb() ((void(*)(void))0xffff0fa0)() |
| 69 | "sub pc, r0, #95" ::: "r0", "lr", "cc", \ | ||
| 70 | "memory") | ||
| 71 | #define cpu_relax() asm volatile("":::"memory") | 69 | #define cpu_relax() asm volatile("":::"memory") |
| 72 | #endif | 70 | #endif |
| 73 | 71 | ||
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c new file mode 100644 index 000000000000..4e01490e51e5 --- /dev/null +++ b/tools/perf/util/cpumap.c | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #include "util.h" | ||
| 2 | #include "../perf.h" | ||
| 3 | #include "cpumap.h" | ||
| 4 | #include <assert.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | |||
| 7 | int cpumap[MAX_NR_CPUS]; | ||
| 8 | |||
| 9 | static int default_cpu_map(void) | ||
| 10 | { | ||
| 11 | int nr_cpus, i; | ||
| 12 | |||
| 13 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
| 14 | assert(nr_cpus <= MAX_NR_CPUS); | ||
| 15 | assert((int)nr_cpus >= 0); | ||
| 16 | |||
| 17 | for (i = 0; i < nr_cpus; ++i) | ||
| 18 | cpumap[i] = i; | ||
| 19 | |||
| 20 | return nr_cpus; | ||
| 21 | } | ||
| 22 | |||
| 23 | int read_cpu_map(void) | ||
| 24 | { | ||
| 25 | FILE *onlnf; | ||
| 26 | int nr_cpus = 0; | ||
| 27 | int n, cpu, prev; | ||
| 28 | char sep; | ||
| 29 | |||
| 30 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
| 31 | if (!onlnf) | ||
| 32 | return default_cpu_map(); | ||
| 33 | |||
| 34 | sep = 0; | ||
| 35 | prev = -1; | ||
| 36 | for (;;) { | ||
| 37 | n = fscanf(onlnf, "%u%c", &cpu, &sep); | ||
| 38 | if (n <= 0) | ||
| 39 | break; | ||
| 40 | if (prev >= 0) { | ||
| 41 | assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); | ||
| 42 | while (++prev < cpu) | ||
| 43 | cpumap[nr_cpus++] = prev; | ||
| 44 | } | ||
| 45 | assert (nr_cpus < MAX_NR_CPUS); | ||
| 46 | cpumap[nr_cpus++] = cpu; | ||
| 47 | if (n == 2 && sep == '-') | ||
| 48 | prev = cpu; | ||
| 49 | else | ||
| 50 | prev = -1; | ||
| 51 | if (n == 1 || sep == '\n') | ||
| 52 | break; | ||
| 53 | } | ||
| 54 | fclose(onlnf); | ||
| 55 | if (nr_cpus > 0) | ||
| 56 | return nr_cpus; | ||
| 57 | |||
| 58 | return default_cpu_map(); | ||
| 59 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h new file mode 100644 index 000000000000..86c78bb33098 --- /dev/null +++ b/tools/perf/util/cpumap.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef __PERF_CPUMAP_H | ||
| 2 | #define __PERF_CPUMAP_H | ||
| 3 | |||
| 4 | extern int read_cpu_map(void); | ||
| 5 | extern int cpumap[]; | ||
| 6 | |||
| 7 | #endif /* __PERF_CPUMAP_H */ | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 50a7132887f5..a33b94952e34 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -99,6 +99,15 @@ struct events_stats { | |||
| 99 | u64 lost; | 99 | u64 lost; |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | struct event_stat_id { | ||
| 103 | struct rb_node rb_node; | ||
| 104 | struct rb_root hists; | ||
| 105 | struct events_stats stats; | ||
| 106 | u64 config; | ||
| 107 | u64 event_stream; | ||
| 108 | u32 type; | ||
| 109 | }; | ||
| 110 | |||
| 102 | void event__print_totals(void); | 111 | void event__print_totals(void); |
| 103 | 112 | ||
| 104 | struct perf_session; | 113 | struct perf_session; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e8daf5ca6fd2..2be33c7dbf03 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -12,12 +12,12 @@ struct callchain_param callchain_param = { | |||
| 12 | * histogram, sorted on item, collects counts | 12 | * histogram, sorted on item, collects counts |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | 15 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, |
| 16 | struct addr_location *al, | 16 | struct addr_location *al, |
| 17 | struct symbol *sym_parent, | 17 | struct symbol *sym_parent, |
| 18 | u64 count, bool *hit) | 18 | u64 count, bool *hit) |
| 19 | { | 19 | { |
| 20 | struct rb_node **p = &self->hists.rb_node; | 20 | struct rb_node **p = &hists->rb_node; |
| 21 | struct rb_node *parent = NULL; | 21 | struct rb_node *parent = NULL; |
| 22 | struct hist_entry *he; | 22 | struct hist_entry *he; |
| 23 | struct hist_entry entry = { | 23 | struct hist_entry entry = { |
| @@ -53,7 +53,7 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | |||
| 53 | return NULL; | 53 | return NULL; |
| 54 | *he = entry; | 54 | *he = entry; |
| 55 | rb_link_node(&he->rb_node, parent, p); | 55 | rb_link_node(&he->rb_node, parent, p); |
| 56 | rb_insert_color(&he->rb_node, &self->hists); | 56 | rb_insert_color(&he->rb_node, hists); |
| 57 | *hit = false; | 57 | *hit = false; |
| 58 | return he; | 58 | return he; |
| 59 | } | 59 | } |
| @@ -130,7 +130,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he) | |||
| 130 | rb_insert_color(&he->rb_node, root); | 130 | rb_insert_color(&he->rb_node, root); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | void perf_session__collapse_resort(struct perf_session *self) | 133 | void perf_session__collapse_resort(struct rb_root *hists) |
| 134 | { | 134 | { |
| 135 | struct rb_root tmp; | 135 | struct rb_root tmp; |
| 136 | struct rb_node *next; | 136 | struct rb_node *next; |
| @@ -140,17 +140,17 @@ void perf_session__collapse_resort(struct perf_session *self) | |||
| 140 | return; | 140 | return; |
| 141 | 141 | ||
| 142 | tmp = RB_ROOT; | 142 | tmp = RB_ROOT; |
| 143 | next = rb_first(&self->hists); | 143 | next = rb_first(hists); |
| 144 | 144 | ||
| 145 | while (next) { | 145 | while (next) { |
| 146 | n = rb_entry(next, struct hist_entry, rb_node); | 146 | n = rb_entry(next, struct hist_entry, rb_node); |
| 147 | next = rb_next(&n->rb_node); | 147 | next = rb_next(&n->rb_node); |
| 148 | 148 | ||
| 149 | rb_erase(&n->rb_node, &self->hists); | 149 | rb_erase(&n->rb_node, hists); |
| 150 | collapse__insert_entry(&tmp, n); | 150 | collapse__insert_entry(&tmp, n); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | self->hists = tmp; | 153 | *hists = tmp; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| @@ -183,7 +183,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root, | |||
| 183 | rb_insert_color(&he->rb_node, root); | 183 | rb_insert_color(&he->rb_node, root); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | void perf_session__output_resort(struct perf_session *self, u64 total_samples) | 186 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples) |
| 187 | { | 187 | { |
| 188 | struct rb_root tmp; | 188 | struct rb_root tmp; |
| 189 | struct rb_node *next; | 189 | struct rb_node *next; |
| @@ -194,18 +194,18 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples) | |||
| 194 | total_samples * (callchain_param.min_percent / 100); | 194 | total_samples * (callchain_param.min_percent / 100); |
| 195 | 195 | ||
| 196 | tmp = RB_ROOT; | 196 | tmp = RB_ROOT; |
| 197 | next = rb_first(&self->hists); | 197 | next = rb_first(hists); |
| 198 | 198 | ||
| 199 | while (next) { | 199 | while (next) { |
| 200 | n = rb_entry(next, struct hist_entry, rb_node); | 200 | n = rb_entry(next, struct hist_entry, rb_node); |
| 201 | next = rb_next(&n->rb_node); | 201 | next = rb_next(&n->rb_node); |
| 202 | 202 | ||
| 203 | rb_erase(&n->rb_node, &self->hists); | 203 | rb_erase(&n->rb_node, hists); |
| 204 | perf_session__insert_output_hist_entry(&tmp, n, | 204 | perf_session__insert_output_hist_entry(&tmp, n, |
| 205 | min_callchain_hits); | 205 | min_callchain_hits); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | self->hists = tmp; | 208 | *hists = tmp; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 211 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
| @@ -321,7 +321,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
| 321 | new_depth_mask &= ~(1 << (depth - 1)); | 321 | new_depth_mask &= ~(1 << (depth - 1)); |
| 322 | 322 | ||
| 323 | /* | 323 | /* |
| 324 | * But we keep the older depth mask for the line seperator | 324 | * But we keep the older depth mask for the line separator |
| 325 | * to keep the level link until we reach the last child | 325 | * to keep the level link until we reach the last child |
| 326 | */ | 326 | */ |
| 327 | ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, | 327 | ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, |
| @@ -456,10 +456,10 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | static size_t hist_entry__fprintf(struct hist_entry *self, | 458 | static size_t hist_entry__fprintf(struct hist_entry *self, |
| 459 | struct perf_session *session, | ||
| 460 | struct perf_session *pair_session, | 459 | struct perf_session *pair_session, |
| 461 | bool show_displacement, | 460 | bool show_displacement, |
| 462 | long displacement, FILE *fp) | 461 | long displacement, FILE *fp, |
| 462 | u64 session_total) | ||
| 463 | { | 463 | { |
| 464 | struct sort_entry *se; | 464 | struct sort_entry *se; |
| 465 | u64 count, total; | 465 | u64 count, total; |
| @@ -474,7 +474,7 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 474 | total = pair_session->events_stats.total; | 474 | total = pair_session->events_stats.total; |
| 475 | } else { | 475 | } else { |
| 476 | count = self->count; | 476 | count = self->count; |
| 477 | total = session->events_stats.total; | 477 | total = session_total; |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | if (total) | 480 | if (total) |
| @@ -496,8 +496,8 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 496 | 496 | ||
| 497 | if (total > 0) | 497 | if (total > 0) |
| 498 | old_percent = (count * 100.0) / total; | 498 | old_percent = (count * 100.0) / total; |
| 499 | if (session->events_stats.total > 0) | 499 | if (session_total > 0) |
| 500 | new_percent = (self->count * 100.0) / session->events_stats.total; | 500 | new_percent = (self->count * 100.0) / session_total; |
| 501 | 501 | ||
| 502 | diff = new_percent - old_percent; | 502 | diff = new_percent - old_percent; |
| 503 | 503 | ||
| @@ -544,16 +544,17 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 544 | left_margin -= thread__comm_len(self->thread); | 544 | left_margin -= thread__comm_len(self->thread); |
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | hist_entry_callchain__fprintf(fp, self, session->events_stats.total, | 547 | hist_entry_callchain__fprintf(fp, self, session_total, |
| 548 | left_margin); | 548 | left_margin); |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | return ret; | 551 | return ret; |
| 552 | } | 552 | } |
| 553 | 553 | ||
| 554 | size_t perf_session__fprintf_hists(struct perf_session *self, | 554 | size_t perf_session__fprintf_hists(struct rb_root *hists, |
| 555 | struct perf_session *pair, | 555 | struct perf_session *pair, |
| 556 | bool show_displacement, FILE *fp) | 556 | bool show_displacement, FILE *fp, |
| 557 | u64 session_total) | ||
| 557 | { | 558 | { |
| 558 | struct sort_entry *se; | 559 | struct sort_entry *se; |
| 559 | struct rb_node *nd; | 560 | struct rb_node *nd; |
| @@ -641,7 +642,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self, | |||
| 641 | fprintf(fp, "\n#\n"); | 642 | fprintf(fp, "\n#\n"); |
| 642 | 643 | ||
| 643 | print_entries: | 644 | print_entries: |
| 644 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | 645 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { |
| 645 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 646 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 646 | 647 | ||
| 647 | if (show_displacement) { | 648 | if (show_displacement) { |
| @@ -652,8 +653,13 @@ print_entries: | |||
| 652 | displacement = 0; | 653 | displacement = 0; |
| 653 | ++position; | 654 | ++position; |
| 654 | } | 655 | } |
| 655 | ret += hist_entry__fprintf(h, self, pair, show_displacement, | 656 | ret += hist_entry__fprintf(h, pair, show_displacement, |
| 656 | displacement, fp); | 657 | displacement, fp, session_total); |
| 658 | if (h->map == NULL && verbose > 1) { | ||
| 659 | __map_groups__fprintf_maps(&h->thread->mg, | ||
| 660 | MAP__FUNCTION, fp); | ||
| 661 | fprintf(fp, "%.10s end\n", graph_dotted_line); | ||
| 662 | } | ||
| 657 | } | 663 | } |
| 658 | 664 | ||
| 659 | free(rem_sq_bracket); | 665 | free(rem_sq_bracket); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e5f99b24048b..16f360cce5bf 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -10,8 +10,9 @@ struct perf_session; | |||
| 10 | struct hist_entry; | 10 | struct hist_entry; |
| 11 | struct addr_location; | 11 | struct addr_location; |
| 12 | struct symbol; | 12 | struct symbol; |
| 13 | struct rb_root; | ||
| 13 | 14 | ||
| 14 | struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | 15 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, |
| 15 | struct addr_location *al, | 16 | struct addr_location *al, |
| 16 | struct symbol *parent, | 17 | struct symbol *parent, |
| 17 | u64 count, bool *hit); | 18 | u64 count, bool *hit); |
| @@ -19,9 +20,10 @@ extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | |||
| 19 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
| 20 | void hist_entry__free(struct hist_entry *); | 21 | void hist_entry__free(struct hist_entry *); |
| 21 | 22 | ||
| 22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); | 23 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples); |
| 23 | void perf_session__collapse_resort(struct perf_session *self); | 24 | void perf_session__collapse_resort(struct rb_root *hists); |
| 24 | size_t perf_session__fprintf_hists(struct perf_session *self, | 25 | size_t perf_session__fprintf_hists(struct rb_root *hists, |
| 25 | struct perf_session *pair, | 26 | struct perf_session *pair, |
| 26 | bool show_displacement, FILE *fp); | 27 | bool show_displacement, FILE *fp, |
| 28 | u64 session_total); | ||
| 27 | #endif /* __PERF_HIST_H */ | 29 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c971e81e9cbf..7c004b6ef24f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -242,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp, | |||
| 242 | 242 | ||
| 243 | /* Parse probe point */ | 243 | /* Parse probe point */ |
| 244 | parse_perf_probe_probepoint(argv[0], pp); | 244 | parse_perf_probe_probepoint(argv[0], pp); |
| 245 | if (pp->file || pp->line) | 245 | if (pp->file || pp->line || pp->lazy_line) |
| 246 | *need_dwarf = true; | 246 | *need_dwarf = true; |
| 247 | 247 | ||
| 248 | /* Copy arguments and ensure return probe has no C argument */ | 248 | /* Copy arguments and ensure return probe has no C argument */ |
| @@ -508,8 +508,8 @@ void show_perf_probe_events(void) | |||
| 508 | struct str_node *ent; | 508 | struct str_node *ent; |
| 509 | 509 | ||
| 510 | setup_pager(); | 510 | setup_pager(); |
| 511 | |||
| 512 | memset(&pp, 0, sizeof(pp)); | 511 | memset(&pp, 0, sizeof(pp)); |
| 512 | |||
| 513 | fd = open_kprobe_events(O_RDONLY, 0); | 513 | fd = open_kprobe_events(O_RDONLY, 0); |
| 514 | rawlist = get_trace_kprobe_event_rawlist(fd); | 514 | rawlist = get_trace_kprobe_event_rawlist(fd); |
| 515 | close(fd); | 515 | close(fd); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e77dc886760e..c171a243d05b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -169,7 +169,7 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | |||
| 169 | { | 169 | { |
| 170 | Dwarf_Files *files; | 170 | Dwarf_Files *files; |
| 171 | size_t nfiles, i; | 171 | size_t nfiles, i; |
| 172 | const char *src; | 172 | const char *src = NULL; |
| 173 | int ret; | 173 | int ret; |
| 174 | 174 | ||
| 175 | if (!fname) | 175 | if (!fname) |
| @@ -333,8 +333,8 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) | |||
| 333 | die("%u exceeds max register number.", regn); | 333 | die("%u exceeds max register number.", regn); |
| 334 | 334 | ||
| 335 | if (deref) | 335 | if (deref) |
| 336 | ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", | 336 | ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", |
| 337 | pf->var, (uintmax_t)offs, regs); | 337 | pf->var, (intmax_t)offs, regs); |
| 338 | else | 338 | else |
| 339 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); | 339 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); |
| 340 | DIE_IF(ret < 0); | 340 | DIE_IF(ret < 0); |
| @@ -352,8 +352,7 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
| 352 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) | 352 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
| 353 | goto error; | 353 | goto error; |
| 354 | /* TODO: handle more than 1 exprs */ | 354 | /* TODO: handle more than 1 exprs */ |
| 355 | ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), | 355 | ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); |
| 356 | &expr, &nexpr, 1); | ||
| 357 | if (ret <= 0 || nexpr == 0) | 356 | if (ret <= 0 || nexpr == 0) |
| 358 | goto error; | 357 | goto error; |
| 359 | 358 | ||
| @@ -437,8 +436,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 437 | 436 | ||
| 438 | /* Get the frame base attribute/ops */ | 437 | /* Get the frame base attribute/ops */ |
| 439 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 438 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
| 440 | ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), | 439 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
| 441 | &pf->fb_ops, &nops, 1); | ||
| 442 | if (ret <= 0 || nops == 0) | 440 | if (ret <= 0 || nops == 0) |
| 443 | pf->fb_ops = NULL; | 441 | pf->fb_ops = NULL; |
| 444 | 442 | ||
| @@ -455,6 +453,9 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 455 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 453 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
| 456 | pf->fb_ops = NULL; | 454 | pf->fb_ops = NULL; |
| 457 | 455 | ||
| 456 | if (pp->found == MAX_PROBES) | ||
| 457 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
| 458 | |||
| 458 | pp->probes[pp->found] = strdup(tmp); | 459 | pp->probes[pp->found] = strdup(tmp); |
| 459 | pp->found++; | 460 | pp->found++; |
| 460 | } | 461 | } |
| @@ -641,7 +642,6 @@ static void find_probe_point_by_func(struct probe_finder *pf) | |||
| 641 | int find_probe_point(int fd, struct probe_point *pp) | 642 | int find_probe_point(int fd, struct probe_point *pp) |
| 642 | { | 643 | { |
| 643 | struct probe_finder pf = {.pp = pp}; | 644 | struct probe_finder pf = {.pp = pp}; |
| 644 | int ret; | ||
| 645 | Dwarf_Off off, noff; | 645 | Dwarf_Off off, noff; |
| 646 | size_t cuhl; | 646 | size_t cuhl; |
| 647 | Dwarf_Die *diep; | 647 | Dwarf_Die *diep; |
| @@ -668,10 +668,6 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
| 668 | pf.fname = NULL; | 668 | pf.fname = NULL; |
| 669 | 669 | ||
| 670 | if (!pp->file || pf.fname) { | 670 | if (!pp->file || pf.fname) { |
| 671 | /* Save CU base address (for frame_base) */ | ||
| 672 | ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); | ||
| 673 | if (ret != 0) | ||
| 674 | pf.cu_base = 0; | ||
| 675 | if (pp->function) | 671 | if (pp->function) |
| 676 | find_probe_point_by_func(&pf); | 672 | find_probe_point_by_func(&pf); |
| 677 | else if (pp->lazy_line) | 673 | else if (pp->lazy_line) |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index d1a651793ba6..21f7354397b4 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -71,7 +71,6 @@ struct probe_finder { | |||
| 71 | 71 | ||
| 72 | /* For variable searching */ | 72 | /* For variable searching */ |
| 73 | Dwarf_Op *fb_ops; /* Frame base attribute */ | 73 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
| 74 | Dwarf_Addr cu_base; /* Current CU base address */ | ||
| 75 | const char *var; /* Current variable name */ | 74 | const char *var; /* Current variable name */ |
| 76 | char *buf; /* Current output buffer */ | 75 | char *buf; /* Current output buffer */ |
| 77 | int len; /* Length of output buffer */ | 76 | int len; /* Length of output buffer */ |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 33a414bbba3e..6a72f14c5986 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data, | |||
| 208 | int size __unused, | 208 | int size __unused, |
| 209 | unsigned long long nsecs, char *comm) | 209 | unsigned long long nsecs, char *comm) |
| 210 | { | 210 | { |
| 211 | PyObject *handler, *retval, *context, *t; | 211 | PyObject *handler, *retval, *context, *t, *obj; |
| 212 | static char handler_name[256]; | 212 | static char handler_name[256]; |
| 213 | struct format_field *field; | 213 | struct format_field *field; |
| 214 | unsigned long long val; | 214 | unsigned long long val; |
| @@ -256,16 +256,23 @@ static void python_process_event(int cpu, void *data, | |||
| 256 | offset &= 0xffff; | 256 | offset &= 0xffff; |
| 257 | } else | 257 | } else |
| 258 | offset = field->offset; | 258 | offset = field->offset; |
| 259 | PyTuple_SetItem(t, n++, | 259 | obj = PyString_FromString((char *)data + offset); |
| 260 | PyString_FromString((char *)data + offset)); | ||
| 261 | } else { /* FIELD_IS_NUMERIC */ | 260 | } else { /* FIELD_IS_NUMERIC */ |
| 262 | val = read_size(data + field->offset, field->size); | 261 | val = read_size(data + field->offset, field->size); |
| 263 | if (field->flags & FIELD_IS_SIGNED) { | 262 | if (field->flags & FIELD_IS_SIGNED) { |
| 264 | PyTuple_SetItem(t, n++, PyInt_FromLong(val)); | 263 | if ((long long)val >= LONG_MIN && |
| 264 | (long long)val <= LONG_MAX) | ||
| 265 | obj = PyInt_FromLong(val); | ||
| 266 | else | ||
| 267 | obj = PyLong_FromLongLong(val); | ||
| 265 | } else { | 268 | } else { |
| 266 | PyTuple_SetItem(t, n++, PyInt_FromLong(val)); | 269 | if (val <= LONG_MAX) |
| 270 | obj = PyInt_FromLong(val); | ||
| 271 | else | ||
| 272 | obj = PyLong_FromUnsignedLongLong(val); | ||
| 267 | } | 273 | } |
| 268 | } | 274 | } |
| 275 | PyTuple_SetItem(t, n++, obj); | ||
| 269 | } | 276 | } |
| 270 | 277 | ||
| 271 | if (_PyTuple_Resize(&t, n) == -1) | 278 | if (_PyTuple_Resize(&t, n) == -1) |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0de7258e70a5..eed1cb889008 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -70,6 +70,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc | |||
| 70 | 70 | ||
| 71 | memcpy(self->filename, filename, len); | 71 | memcpy(self->filename, filename, len); |
| 72 | self->threads = RB_ROOT; | 72 | self->threads = RB_ROOT; |
| 73 | self->stats_by_id = RB_ROOT; | ||
| 73 | self->last_match = NULL; | 74 | self->last_match = NULL; |
| 74 | self->mmap_window = 32; | 75 | self->mmap_window = 32; |
| 75 | self->cwd = NULL; | 76 | self->cwd = NULL; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 31950fcd8a4d..5c33417eebb3 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -20,6 +20,7 @@ struct perf_session { | |||
| 20 | struct thread *last_match; | 20 | struct thread *last_match; |
| 21 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 21 | struct map *vmlinux_maps[MAP__NR_TYPES]; |
| 22 | struct events_stats events_stats; | 22 | struct events_stats events_stats; |
| 23 | struct rb_root stats_by_id; | ||
| 23 | unsigned long event_total[PERF_RECORD_MAX]; | 24 | unsigned long event_total[PERF_RECORD_MAX]; |
| 24 | unsigned long unknown_events; | 25 | unsigned long unknown_events; |
| 25 | struct rb_root hists; | 26 | struct rb_root hists; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 323c0aea0a91..c458c4a371d1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -163,9 +163,17 @@ void dso__set_long_name(struct dso *self, char *name) | |||
| 163 | self->long_name_len = strlen(name); | 163 | self->long_name_len = strlen(name); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static void dso__set_short_name(struct dso *self, const char *name) | ||
| 167 | { | ||
| 168 | if (name == NULL) | ||
| 169 | return; | ||
| 170 | self->short_name = name; | ||
| 171 | self->short_name_len = strlen(name); | ||
| 172 | } | ||
| 173 | |||
| 166 | static void dso__set_basename(struct dso *self) | 174 | static void dso__set_basename(struct dso *self) |
| 167 | { | 175 | { |
| 168 | self->short_name = basename(self->long_name); | 176 | dso__set_short_name(self, basename(self->long_name)); |
| 169 | } | 177 | } |
| 170 | 178 | ||
| 171 | struct dso *dso__new(const char *name) | 179 | struct dso *dso__new(const char *name) |
| @@ -176,7 +184,7 @@ struct dso *dso__new(const char *name) | |||
| 176 | int i; | 184 | int i; |
| 177 | strcpy(self->name, name); | 185 | strcpy(self->name, name); |
| 178 | dso__set_long_name(self, self->name); | 186 | dso__set_long_name(self, self->name); |
| 179 | self->short_name = self->name; | 187 | dso__set_short_name(self, self->name); |
| 180 | for (i = 0; i < MAP__NR_TYPES; ++i) | 188 | for (i = 0; i < MAP__NR_TYPES; ++i) |
| 181 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; | 189 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; |
| 182 | self->slen_calculated = 0; | 190 | self->slen_calculated = 0; |
| @@ -897,7 +905,6 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 897 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; | 905 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; |
| 898 | struct map *curr_map = map; | 906 | struct map *curr_map = map; |
| 899 | struct dso *curr_dso = self; | 907 | struct dso *curr_dso = self; |
| 900 | size_t dso_name_len = strlen(self->short_name); | ||
| 901 | Elf_Data *symstrs, *secstrs; | 908 | Elf_Data *symstrs, *secstrs; |
| 902 | uint32_t nr_syms; | 909 | uint32_t nr_syms; |
| 903 | int err = -1; | 910 | int err = -1; |
| @@ -987,7 +994,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 987 | char dso_name[PATH_MAX]; | 994 | char dso_name[PATH_MAX]; |
| 988 | 995 | ||
| 989 | if (strcmp(section_name, | 996 | if (strcmp(section_name, |
| 990 | curr_dso->short_name + dso_name_len) == 0) | 997 | (curr_dso->short_name + |
| 998 | self->short_name_len)) == 0) | ||
| 991 | goto new_symbol; | 999 | goto new_symbol; |
| 992 | 1000 | ||
| 993 | if (strcmp(section_name, ".text") == 0) { | 1001 | if (strcmp(section_name, ".text") == 0) { |
| @@ -1782,7 +1790,7 @@ struct dso *dso__new_kernel(const char *name) | |||
| 1782 | struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); | 1790 | struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); |
| 1783 | 1791 | ||
| 1784 | if (self != NULL) { | 1792 | if (self != NULL) { |
| 1785 | self->short_name = "[kernel]"; | 1793 | dso__set_short_name(self, "[kernel]"); |
| 1786 | self->kernel = 1; | 1794 | self->kernel = 1; |
| 1787 | } | 1795 | } |
| 1788 | 1796 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 280dadd32a08..f30a37428919 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -110,9 +110,10 @@ struct dso { | |||
| 110 | u8 sorted_by_name; | 110 | u8 sorted_by_name; |
| 111 | u8 loaded; | 111 | u8 loaded; |
| 112 | u8 build_id[BUILD_ID_SIZE]; | 112 | u8 build_id[BUILD_ID_SIZE]; |
| 113 | u16 long_name_len; | ||
| 114 | const char *short_name; | 113 | const char *short_name; |
| 115 | char *long_name; | 114 | char *long_name; |
| 115 | u16 long_name_len; | ||
| 116 | u16 short_name_len; | ||
| 116 | char name[0]; | 117 | char name[0]; |
| 117 | }; | 118 | }; |
| 118 | 119 | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 21b92162282b..fa968312ee7d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -79,8 +79,8 @@ int thread__comm_len(struct thread *self) | |||
| 79 | return self->comm_len; | 79 | return self->comm_len; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static size_t __map_groups__fprintf_maps(struct map_groups *self, | 82 | size_t __map_groups__fprintf_maps(struct map_groups *self, |
| 83 | enum map_type type, FILE *fp) | 83 | enum map_type type, FILE *fp) |
| 84 | { | 84 | { |
| 85 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | 85 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); |
| 86 | struct rb_node *nd; | 86 | struct rb_node *nd; |
| @@ -89,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self, | |||
| 89 | struct map *pos = rb_entry(nd, struct map, rb_node); | 89 | struct map *pos = rb_entry(nd, struct map, rb_node); |
| 90 | printed += fprintf(fp, "Map:"); | 90 | printed += fprintf(fp, "Map:"); |
| 91 | printed += map__fprintf(pos, fp); | 91 | printed += map__fprintf(pos, fp); |
| 92 | if (verbose > 1) { | 92 | if (verbose > 2) { |
| 93 | printed += dso__fprintf(pos->dso, type, fp); | 93 | printed += dso__fprintf(pos->dso, type, fp); |
| 94 | printed += fprintf(fp, "--\n"); | 94 | printed += fprintf(fp, "--\n"); |
| 95 | } | 95 | } |
| @@ -183,8 +183,8 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | |||
| 183 | return th; | 183 | return th; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static void map_groups__remove_overlappings(struct map_groups *self, | 186 | static int map_groups__fixup_overlappings(struct map_groups *self, |
| 187 | struct map *map) | 187 | struct map *map) |
| 188 | { | 188 | { |
| 189 | struct rb_root *root = &self->maps[map->type]; | 189 | struct rb_root *root = &self->maps[map->type]; |
| 190 | struct rb_node *next = rb_first(root); | 190 | struct rb_node *next = rb_first(root); |
| @@ -209,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self, | |||
| 209 | * list. | 209 | * list. |
| 210 | */ | 210 | */ |
| 211 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | 211 | list_add_tail(&pos->node, &self->removed_maps[map->type]); |
| 212 | /* | ||
| 213 | * Now check if we need to create new maps for areas not | ||
| 214 | * overlapped by the new map: | ||
| 215 | */ | ||
| 216 | if (map->start > pos->start) { | ||
| 217 | struct map *before = map__clone(pos); | ||
| 218 | |||
| 219 | if (before == NULL) | ||
| 220 | return -ENOMEM; | ||
| 221 | |||
| 222 | before->end = map->start - 1; | ||
| 223 | map_groups__insert(self, before); | ||
| 224 | if (verbose >= 2) | ||
| 225 | map__fprintf(before, stderr); | ||
| 226 | } | ||
| 227 | |||
| 228 | if (map->end < pos->end) { | ||
| 229 | struct map *after = map__clone(pos); | ||
| 230 | |||
| 231 | if (after == NULL) | ||
| 232 | return -ENOMEM; | ||
| 233 | |||
| 234 | after->start = map->end + 1; | ||
| 235 | map_groups__insert(self, after); | ||
| 236 | if (verbose >= 2) | ||
| 237 | map__fprintf(after, stderr); | ||
| 238 | } | ||
| 212 | } | 239 | } |
| 240 | |||
| 241 | return 0; | ||
| 213 | } | 242 | } |
| 214 | 243 | ||
| 215 | void maps__insert(struct rb_root *maps, struct map *map) | 244 | void maps__insert(struct rb_root *maps, struct map *map) |
| @@ -254,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
| 254 | 283 | ||
| 255 | void thread__insert_map(struct thread *self, struct map *map) | 284 | void thread__insert_map(struct thread *self, struct map *map) |
| 256 | { | 285 | { |
| 257 | map_groups__remove_overlappings(&self->mg, map); | 286 | map_groups__fixup_overlappings(&self->mg, map); |
| 258 | map_groups__insert(&self->mg, map); | 287 | map_groups__insert(&self->mg, map); |
| 259 | } | 288 | } |
| 260 | 289 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 0a28f39de545..dcf70303e58e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
| @@ -10,6 +10,9 @@ struct map_groups { | |||
| 10 | struct list_head removed_maps[MAP__NR_TYPES]; | 10 | struct list_head removed_maps[MAP__NR_TYPES]; |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | size_t __map_groups__fprintf_maps(struct map_groups *self, | ||
| 14 | enum map_type type, FILE *fp); | ||
| 15 | |||
| 13 | struct thread { | 16 | struct thread { |
| 14 | struct rb_node rb_node; | 17 | struct rb_node rb_node; |
| 15 | struct map_groups mg; | 18 | struct map_groups mg; |
