diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-05-03 09:17:01 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-05-03 09:17:01 +0200 |
commit | 53ba4f2fa73225113a488584df0d85d3cba52943 (patch) | |
tree | d85b984d9818abc3ccc0237eb53b710d9e96c39e /tools | |
parent | bd6d29c25bb1a24a4c160ec5de43e0004e01f72b (diff) | |
parent | 66f41d4c5c8a5deed66fdcc84509376c9a0bf9d8 (diff) |
Merge commit 'v2.6.34-rc6' into core/locking
Diffstat (limited to 'tools')
34 files changed, 1155 insertions, 729 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index bdd3b7ecad0..bd498d49695 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile @@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT)) DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) +# Make the path relative to DESTDIR, not prefix +ifndef DESTDIR prefix?=$(HOME) +endif bindir?=$(prefix)/bin htmldir?=$(prefix)/share/doc/perf-doc pdfdir?=$(prefix)/share/doc/perf-doc @@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man man1dir=$(mandir)/man1 man5dir=$(mandir)/man5 man7dir=$(mandir)/man7 -# DESTDIR= ASCIIDOC=asciidoc ASCIIDOC_EXTRA = --unsafe diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt new file mode 100644 index 00000000000..b317102138c --- /dev/null +++ b/tools/perf/Documentation/perf-lock.txt @@ -0,0 +1,29 @@ +perf-lock(1) +============ + +NAME +---- +perf-lock - Analyze lock events + +SYNOPSIS +-------- +[verse] +'perf lock' {record|report|trace} + +DESCRIPTION +----------- +You can analyze various lock behaviours +and statistics with this 'perf lock' command. + + 'perf lock record <command>' records lock events + between start and end <command>. And this command + produces the file "perf.data" which contains tracing + results of lock events. + + 'perf lock trace' shows raw lock events. + + 'perf lock report' reports statistical data. + +SEE ALSO +-------- +linkperf:perf[1] diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 2de34075f6a..34202b1be0b 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -41,7 +41,8 @@ OPTIONS -d:: --del=:: - Delete a probe event. + Delete probe events. This accepts glob wildcards('*', '?') and character + classes(e.g. [a-z], [!A-Z]). -l:: --list:: @@ -50,17 +51,29 @@ OPTIONS -L:: --line=:: Show source code lines which can be probed. This needs an argument - which specifies a range of the source code. + which specifies a range of the source code. (see LINE SYNTAX for detail) + +-f:: +--force:: + Forcibly add events with existing name. PROBE SYNTAX ------------ Probe points are defined by following syntax. - "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" + 1) Define event based on function name + [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] + + 2) Define event based on source file with line number + [EVENT=]SRC:ALN [ARG ...] + + 3) Define event based on source file with lazy pattern + [EVENT=]SRC;PTN [ARG ...] + 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. -'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. -It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. +'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. +It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. 'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). LINE SYNTAX @@ -76,6 +89,41 @@ and 'ALN2' is end line number in the file. It is also possible to specify how many lines to show by using 'NUM'. So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. +LAZY MATCHING +------------- + The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]). + +e.g. + 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on. + +This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.) + + +EXAMPLES +-------- +Display which lines in schedule() can be probed: + + ./perf probe --line schedule + +Add a probe on schedule() function 12th line with recording cpu local variable: + + ./perf probe schedule:12 cpu + or + ./perf probe --add='schedule:12 cpu' + + this will add one or more probes which has the name start with "schedule". + + Add probes on lines in schedule() function which calls update_rq_clock(). + + ./perf probe 'schedule;update_rq_clock*' + or + ./perf probe --add='schedule;update_rq_clock*' + +Delete all probes on schedule(). + + ./perf probe --del='schedule*' + + SEE ALSO -------- linkperf:perf-trace[1], linkperf:perf-record[1] diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 54a5b50ff31..bc0f670a833 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -200,7 +200,7 @@ endif CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) EXTLIBS = -lpthread -lrt -lelf -lm -ALL_CFLAGS = $(CFLAGS) +ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip @@ -216,7 +216,10 @@ STRIP ?= strip # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. +# Make the path relative to DESTDIR, not to prefix +ifndef DESTDIR prefix = $(HOME) +endif bindir_relative = bin bindir = $(prefix)/$(bindir_relative) mandir = share/man @@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc ETC_PERFCONFIG = etc/perfconfig endif lib = lib -# DESTDIR= export prefix bindir sharedir sysconfdir @@ -387,6 +389,7 @@ LIB_H += util/thread.h LIB_H += util/trace-event.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h +LIB_H += util/cpumap.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o @@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o LIB_OBJS += util/hist.o LIB_OBJS += util/probe-event.o LIB_OBJS += util/util.o +LIB_OBJS += util/cpumap.o BUILTIN_OBJS += builtin-annotate.o @@ -488,24 +492,24 @@ ifeq ($(uname_S),Darwin) PTHREAD_LIBS = endif -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) -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) +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) +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) msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); endif - 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) + 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) BASIC_CFLAGS += -DLIBELF_NO_MMAP endif else msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); endif -ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) - msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); - BASIC_CFLAGS += -DNO_LIBDWARF +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) + msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); + BASIC_CFLAGS += -DNO_DWARF_SUPPORT else - BASIC_CFLAGS += -I/usr/include/libdwarf - EXTLIBS += -lelf -ldwarf + BASIC_CFLAGS += -I/usr/include/elfutils + EXTLIBS += -lelf -ldw LIB_OBJS += util/probe-finder.o endif diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5ec5de99587..6ad7148451c 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, return 0; } - he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); + he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit); if (he == NULL) return -ENOMEM; @@ -564,8 +564,8 @@ static int __cmd_annotate(void) if (verbose > 2) dsos__fprintf(stdout); - perf_session__collapse_resort(session); - perf_session__output_resort(session, session->event_total[0]); + perf_session__collapse_resort(&session->hists); + perf_session__output_resort(&session->hists, session->event_total[0]); perf_session__find_annotations(session); out_delete: perf_session__delete(session); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 18b3f505f9d..1ea15d8aeed 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, struct addr_location *al, u64 count) { bool hit; - struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, + struct hist_entry *he = __perf_session__add_hist_entry(&self->hists, + al, NULL, count, &hit); if (he == NULL) return -ENOMEM; @@ -114,7 +115,7 @@ static void perf_session__resort_hist_entries(struct perf_session *self) static void perf_session__set_hist_entries_positions(struct perf_session *self) { - perf_session__output_resort(self, self->events_stats.total); + perf_session__output_resort(&self->hists, self->events_stats.total); perf_session__resort_hist_entries(self); } @@ -166,13 +167,15 @@ static int __cmd_diff(void) goto out_delete; } - perf_session__output_resort(session[1], session[1]->events_stats.total); + perf_session__output_resort(&session[1]->hists, + session[1]->events_stats.total); if (show_displacement) perf_session__set_hist_entries_positions(session[0]); perf_session__match_hists(session[0], session[1]); - perf_session__fprintf_hists(session[1], session[0], - show_displacement, stdout); + perf_session__fprintf_hists(&session[1]->hists, session[0], + show_displacement, stdout, + session[1]->events_stats.total); out_delete: for (i = 0; i < 2; ++i) perf_session__delete(session[i]); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index fb9ab2ad3f9..e12c844df1e 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -460,6 +460,150 @@ process_raw_event(void *data, int cpu, process_lock_release_event(data, event, cpu, timestamp, thread); } +struct raw_event_queue { + u64 timestamp; + int cpu; + void *data; + struct thread *thread; + struct list_head list; +}; + +static LIST_HEAD(raw_event_head); + +#define FLUSH_PERIOD (5 * NSEC_PER_SEC) + +static u64 flush_limit = ULLONG_MAX; +static u64 last_flush = 0; +struct raw_event_queue *last_inserted; + +static void flush_raw_event_queue(u64 limit) +{ + struct raw_event_queue *tmp, *iter; + + list_for_each_entry_safe(iter, tmp, &raw_event_head, list) { + if (iter->timestamp > limit) + return; + + if (iter == last_inserted) + last_inserted = NULL; + + process_raw_event(iter->data, iter->cpu, iter->timestamp, + iter->thread); + + last_flush = iter->timestamp; + list_del(&iter->list); + free(iter->data); + free(iter); + } +} + +static void __queue_raw_event_end(struct raw_event_queue *new) +{ + struct raw_event_queue *iter; + + list_for_each_entry_reverse(iter, &raw_event_head, list) { + if (iter->timestamp < new->timestamp) { + list_add(&new->list, &iter->list); + return; + } + } + + list_add(&new->list, &raw_event_head); +} + +static void __queue_raw_event_before(struct raw_event_queue *new, + struct raw_event_queue *iter) +{ + list_for_each_entry_continue_reverse(iter, &raw_event_head, list) { + if (iter->timestamp < new->timestamp) { + list_add(&new->list, &iter->list); + return; + } + } + + list_add(&new->list, &raw_event_head); +} + +static void __queue_raw_event_after(struct raw_event_queue *new, + struct raw_event_queue *iter) +{ + list_for_each_entry_continue(iter, &raw_event_head, list) { + if (iter->timestamp > new->timestamp) { + list_add_tail(&new->list, &iter->list); + return; + } + } + list_add_tail(&new->list, &raw_event_head); +} + +/* The queue is ordered by time */ +static void __queue_raw_event(struct raw_event_queue *new) +{ + if (!last_inserted) { + __queue_raw_event_end(new); + return; + } + + /* + * Most of the time the current event has a timestamp + * very close to the last event inserted, unless we just switched + * to another event buffer. Having a sorting based on a list and + * on the last inserted event that is close to the current one is + * probably more efficient than an rbtree based sorting. + */ + if (last_inserted->timestamp >= new->timestamp) + __queue_raw_event_before(new, last_inserted); + else + __queue_raw_event_after(new, last_inserted); +} + +static void queue_raw_event(void *data, int raw_size, int cpu, + u64 timestamp, struct thread *thread) +{ + struct raw_event_queue *new; + + if (flush_limit == ULLONG_MAX) + flush_limit = timestamp + FLUSH_PERIOD; + + if (timestamp < last_flush) { + printf("Warning: Timestamp below last timeslice flush\n"); + return; + } + + new = malloc(sizeof(*new)); + if (!new) + die("Not enough memory\n"); + + new->timestamp = timestamp; + new->cpu = cpu; + new->thread = thread; + + new->data = malloc(raw_size); + if (!new->data) + die("Not enough memory\n"); + + memcpy(new->data, data, raw_size); + + __queue_raw_event(new); + last_inserted = new; + + /* + * We want to have a slice of events covering 2 * FLUSH_PERIOD + * If FLUSH_PERIOD is big enough, it ensures every events that occured + * in the first half of the timeslice have all been buffered and there + * are none remaining (we need that because of the weakly ordered + * event recording we have). Then once we reach the 2 * FLUSH_PERIOD + * timeslice, we flush the first half to be gentle with the memory + * (the second half can still get new events in the middle, so wait + * another period to flush it) + */ + if (new->timestamp > flush_limit && + new->timestamp - flush_limit > FLUSH_PERIOD) { + flush_limit += FLUSH_PERIOD; + flush_raw_event_queue(flush_limit); + } +} + static int process_sample_event(event_t *event, struct perf_session *session) { struct thread *thread; @@ -480,7 +624,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) if (profile_cpu != -1 && profile_cpu != (int) data.cpu) return 0; - process_raw_event(data.raw_data, data.cpu, data.time, thread); + queue_raw_event(data.raw_data, data.raw_size, data.cpu, data.time, thread); return 0; } @@ -576,6 +720,7 @@ static void __cmd_report(void) setup_pager(); select_key(); read_events(); + flush_raw_event_queue(ULLONG_MAX); sort_result(); print_result(); } @@ -608,7 +753,6 @@ static const char *record_args[] = { "record", "-a", "-R", - "-M", "-f", "-m", "1024", "-c", "1", diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index ad47bd4c50e..152d6c9b1fa 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -47,7 +47,6 @@ #include "util/probe-event.h" #define MAX_PATH_LEN 256 -#define MAX_PROBES 128 /* Session management structure */ static struct { @@ -128,7 +127,7 @@ static void evaluate_probe_point(struct probe_point *pp) pp->function); } -#ifndef NO_LIBDWARF +#ifndef NO_DWARF_SUPPORT static int open_vmlinux(void) { if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { @@ -156,14 +155,16 @@ static const char * const probe_usage[] = { "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", "perf probe [<options>] --del '[GROUP:]EVENT' ...", "perf probe --list", +#ifndef NO_DWARF_SUPPORT "perf probe --line 'LINEDESC'", +#endif NULL }; static const struct option options[] = { OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show parsed arguments, etc)"), -#ifndef NO_LIBDWARF +#ifndef NO_DWARF_SUPPORT OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), #endif @@ -172,30 +173,32 @@ static const struct option options[] = { OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", opt_del_probe_event), OPT_CALLBACK('a', "add", NULL, -#ifdef NO_LIBDWARF - "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", +#ifdef NO_DWARF_SUPPORT + "[EVENT=]FUNC[+OFF|%return] [ARG ...]", #else - "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", + "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" + " [ARG ...]", #endif "probe point definition, where\n" "\t\tGROUP:\tGroup name (optional)\n" "\t\tEVENT:\tEvent name\n" "\t\tFUNC:\tFunction name\n" - "\t\tOFFS:\tOffset from function entry (in byte)\n" + "\t\tOFF:\tOffset from function entry (in byte)\n" "\t\t%return:\tPut the probe at function return\n" -#ifdef NO_LIBDWARF +#ifdef NO_DWARF_SUPPORT "\t\tARG:\tProbe argument (only \n" #else "\t\tSRC:\tSource code path\n" - "\t\tRLN:\tRelative line number from function entry.\n" - "\t\tALN:\tAbsolute line number in file.\n" + "\t\tRL:\tRelative line number from function entry.\n" + "\t\tAL:\tAbsolute line number in file.\n" + "\t\tPT:\tLazy expression of line code.\n" "\t\tARG:\tProbe argument (local variable name or\n" #endif "\t\t\tkprobe-tracer argument format.)\n", opt_add_probe_event), OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" " with existing name"), -#ifndef NO_LIBDWARF +#ifndef NO_DWARF_SUPPORT OPT_CALLBACK('L', "line", NULL, "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", "Show source code lines.", opt_show_lines), @@ -223,7 +226,7 @@ static void init_vmlinux(void) int cmd_probe(int argc, const char **argv, const char *prefix __used) { int i, ret; -#ifndef NO_LIBDWARF +#ifndef NO_DWARF_SUPPORT int fd; #endif struct probe_point *pp; @@ -259,7 +262,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) return 0; } -#ifndef NO_LIBDWARF +#ifndef NO_DWARF_SUPPORT if (session.show_lines) { if (session.nr_probe != 0 || session.dellist) { pr_warning(" Error: Don't use --line with" @@ -290,9 +293,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) init_vmlinux(); if (session.need_dwarf) -#ifdef NO_LIBDWARF +#ifdef NO_DWARF_SUPPORT die("Debuginfo-analysis is not supported"); -#else /* !NO_LIBDWARF */ +#else /* !NO_DWARF_SUPPORT */ pr_debug("Some probes require debuginfo.\n"); fd = open_vmlinux(); @@ -312,7 +315,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) continue; lseek(fd, SEEK_SET, 0); - ret = find_probepoint(fd, pp); + ret = find_probe_point(fd, pp); if (ret > 0) continue; if (ret == 0) { /* No error but failed to find probe point. */ @@ -333,7 +336,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) close(fd); end_dwarf: -#endif /* !NO_LIBDWARF */ +#endif /* !NO_DWARF_SUPPORT */ /* Synthesize probes without dwarf */ for (i = 0; i < session.nr_probe; i++) { diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 771533ced6a..3b8b6387c47 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -22,6 +22,7 @@ #include "util/debug.h" #include "util/session.h" #include "util/symbol.h" +#include "util/cpumap.h" #include <unistd.h> #include <sched.h> @@ -244,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid) attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; + if (nr_counters > 1) + attr->sample_type |= PERF_SAMPLE_ID; + if (freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; attr->freq = 1; @@ -391,6 +395,9 @@ static int process_buildids(void) { u64 size = lseek(output, 0, SEEK_CUR); + if (size == 0) + return 0; + session->fd = output; return __perf_session__process_events(session, post_processing_offset, size - post_processing_offset, @@ -418,9 +425,6 @@ static int __cmd_record(int argc, const char **argv) char buf; page_size = sysconf(_SC_PAGE_SIZE); - nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); - assert(nr_cpus <= MAX_NR_CPUS); - assert(nr_cpus >= 0); atexit(sig_atexit); signal(SIGCHLD, sig_handler); @@ -544,8 +548,9 @@ static int __cmd_record(int argc, const char **argv) if ((!system_wide && !inherit) || profile_cpu != -1) { open_counters(profile_cpu, target_pid); } else { + nr_cpus = read_cpu_map(); for (i = 0; i < nr_cpus; i++) - open_counters(i, target_pid); + open_counters(cpumap[i], target_pid); } if (file_new) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cfc655d40bb..f815de25d0f 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; static char callchain_default_opt[] = "fractal,0.5"; +static struct event_stat_id *get_stats(struct perf_session *self, + u64 event_stream, u32 type, u64 config) +{ + struct rb_node **p = &self->stats_by_id.rb_node; + struct rb_node *parent = NULL; + struct event_stat_id *iter, *new; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct event_stat_id, rb_node); + if (iter->config == config) + return iter; + + + if (config > iter->config) + p = &(*p)->rb_right; + else + p = &(*p)->rb_left; + } + + new = malloc(sizeof(struct event_stat_id)); + if (new == NULL) + return NULL; + memset(new, 0, sizeof(struct event_stat_id)); + new->event_stream = event_stream; + new->config = config; + new->type = type; + rb_link_node(&new->rb_node, parent, p); + rb_insert_color(&new->rb_node, &self->stats_by_id); + return new; +} + static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, - struct ip_callchain *chain, u64 count) + struct sample_data *data) { struct symbol **syms = NULL, *parent = NULL; bool hit; struct hist_entry *he; + struct event_stat_id *stats; + struct perf_event_attr *attr; - if ((sort__has_parent || symbol_conf.use_callchain) && chain) + if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) syms = perf_session__resolve_callchain(self, al->thread, - chain, &parent); - he = __perf_session__add_hist_entry(self, al, parent, count, &hit); + data->callchain, &parent); + + attr = perf_header__find_attr(data->id, &self->header); + if (attr) + stats = get_stats(self, data->id, attr->type, attr->config); + else + stats = get_stats(self, data->id, 0, 0); + if (stats == NULL) + return -ENOMEM; + he = __perf_session__add_hist_entry(&stats->hists, al, parent, + data->period, &hit); if (he == NULL) return -ENOMEM; if (hit) - he->count += count; + he->count += data->period; if (symbol_conf.use_callchain) { if (!hit) callchain_init(&he->callchain); - append_chain(&he->callchain, chain, syms); + append_chain(&he->callchain, data->callchain, syms); free(syms); } @@ -86,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) return 0; } +static int add_event_total(struct perf_session *session, + struct sample_data *data, + struct perf_event_attr *attr) +{ + struct event_stat_id *stats; + + if (attr) + stats = get_stats(session, data->id, attr->type, attr->config); + else + stats = get_stats(sessio |