diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/.gitignore | 1 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-timechart.txt | 3 | ||||
-rw-r--r-- | tools/perf/Makefile | 23 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 26 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 6 | ||||
-rw-r--r-- | tools/perf/design.txt | 3 | ||||
-rw-r--r-- | tools/perf/util/module.c | 96 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 54 | ||||
-rw-r--r-- | tools/perf/util/svghelper.c | 14 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 20 | ||||
-rw-r--r-- | tools/perf/util/trace-event-parse.c | 17 |
15 files changed, 185 insertions, 99 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index d69a759a104..0854f110bf7 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -10,6 +10,7 @@ perf-stat perf-top perf*.1 perf*.xml +perf*.html common-cmds.h tags TAGS diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 1c2ed3090cc..a7910099d6f 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt @@ -31,6 +31,9 @@ OPTIONS -w:: --width=:: Select the width of the SVG file (default: 1000) +-p:: +--power-only:: + Only output the CPU power section of the diagram SEE ALSO diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1abbf9a5ee5..1811a7015f9 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -157,11 +157,18 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') -# If we're on a 64-bit kernel, use -m64 -ifndef NO_64BIT - ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) - M64 := -m64 - endif +# +# Add -m32 for cross-builds: +# +ifdef NO_64BIT + MBITS := -m32 +else + # + # If we're on a 64-bit kernel, use -m64: + # + ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) + MBITS := -m64 + endif endif # CFLAGS and LDFLAGS are for the users to override from the command line. @@ -194,7 +201,7 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement -CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) +CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) LDFLAGS = -lpthread -lrt -lelf -lm ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) @@ -418,7 +425,7 @@ ifeq ($(uname_S),Darwin) 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 /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) - msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); + msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); endif ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/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 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) @@ -739,7 +746,7 @@ $(BUILT_INS): perf$X common-cmds.h: util/generate-cmdlist.sh command-list.txt common-cmds.h: $(wildcard Documentation/perf-*.txt) - $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@ + $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)$(RM) $@ $@+ && \ diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a5a050af8e7..3eeef339c78 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -41,6 +41,7 @@ static int raw_samples = 0; static int system_wide = 0; static int profile_cpu = -1; static pid_t target_pid = -1; +static pid_t child_pid = -1; static int inherit = 1; static int force = 0; static int append_file = 0; @@ -184,6 +185,9 @@ static void sig_handler(int sig) static void sig_atexit(void) { + if (child_pid != -1) + kill(child_pid, SIGTERM); + if (signr == -1) return; @@ -610,6 +614,8 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } } + + child_pid = pid; } if (realtime_prio) { diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index ea9c15c0cdf..ce2d5be4f30 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1287,7 +1287,7 @@ static struct sort_dimension *available_sorts[] = { static LIST_HEAD(sort_list); -static int sort_dimension__add(char *tok, struct list_head *list) +static int sort_dimension__add(const char *tok, struct list_head *list) { int i; @@ -1917,7 +1917,7 @@ static void setup_sorting(void) free(str); - sort_dimension__add((char *)"pid", &cmp_pid); + sort_dimension__add("pid", &cmp_pid); } static const char *record_args[] = { diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 16af2d82e85..3db31e7bf17 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -69,7 +69,8 @@ static int run_idx = 0; static int run_count = 1; static int inherit = 1; static int scale = 1; -static int target_pid = -1; +static pid_t target_pid = -1; +static pid_t child_pid = -1; static int null_run = 0; static int fd[MAX_NR_CPUS][MAX_COUNTERS]; @@ -285,6 +286,8 @@ static int run_perf_stat(int argc __used, const char **argv) exit(-1); } + child_pid = pid; + /* * Wait for the child to be ready to exec. */ @@ -338,14 +341,24 @@ static void nsec_printout(int counter, double avg) static void abs_printout(int counter, double avg) { + double total, ratio = 0.0; + fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { - fprintf(stderr, " # %10.3f IPC ", - avg / avg_stats(&runtime_cycles_stats)); + total = avg_stats(&runtime_cycles_stats); + + if (total) + ratio = avg / total; + + fprintf(stderr, " # %10.3f IPC ", ratio); } else { - fprintf(stderr, " # %10.3f M/sec", - 1000.0 * avg / avg_stats(&runtime_nsecs_stats)); + total = avg_stats(&runtime_nsecs_stats); + + if (total) + ratio = 1000.0 * avg / total; + + fprintf(stderr, " # %10.3f M/sec", ratio); } } @@ -423,6 +436,9 @@ static void skip_signal(int signo) static void sig_atexit(void) { + if (child_pid != -1) + kill(child_pid, SIGTERM); + if (signr == -1) return; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4405681b313..702d8fe58fb 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -46,6 +46,8 @@ static u64 turbo_frequency; static u64 first_time, last_time; +static int power_only; + static struct perf_header *header; @@ -547,7 +549,7 @@ static void end_sample_processing(void) u64 cpu; struct power_event *pwr; - for (cpu = 0; cpu < numcpus; cpu++) { + for (cpu = 0; cpu <= numcpus; cpu++) { pwr = malloc(sizeof(struct power_event)); if (!pwr) return; @@ -871,7 +873,7 @@ static int determine_display_tasks(u64 threshold) /* no exit marker, task kept running to the end */ if (p->end_time == 0) p->end_time = last_time; - if (p->total_time >= threshold) + if (p->total_time >= threshold && !power_only) p->display = 1; c = p->all; @@ -882,7 +884,7 @@ static int determine_display_tasks(u64 threshold) if (c->start_time == 1) c->start_time = first_time; - if (c->total_time >= threshold) { + if (c->total_time >= threshold && !power_only) { c->display = 1; count++; } @@ -1134,6 +1136,8 @@ static const struct option options[] = { "output file name"), OPT_INTEGER('w', "width", &svg_page_width, "page width"), + OPT_BOOLEAN('p', "power-only", &power_only, + "output power data only"), OPT_END() }; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1ca88896eee..37512e93623 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -782,6 +782,7 @@ static const char *skip_symbols[] = { "exit_idle", "mwait_idle", "mwait_idle_with_hints", + "poll_idle", "ppc64_runlatch_off", "pseries_dedicated_idle_sleep", NULL diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e9d256e2f47..0c5e4f72f2b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -219,10 +219,6 @@ remap: more: event = (event_t *)(buf + head); - size = event->header.size; - if (!size) - size = 8; - if (head + event->header.size >= page_size * mmap_window) { unsigned long shift = page_size * (head / page_size); int res; @@ -237,7 +233,6 @@ more: size = event->header.size; - if (!size || process_event(event, offset, head) < 0) { /* @@ -290,7 +285,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) usage_with_options(annotate_usage, options); } - setup_pager(); return __cmd_trace(); diff --git a/tools/perf/design.txt b/tools/perf/design.txt index f1946d107b1..fdd42a824c9 100644 --- a/tools/perf/design.txt +++ b/tools/perf/design.txt @@ -455,3 +455,6 @@ will need at least this: If your architecture does have hardware capabilities, you can override the weak stub hw_perf_event_init() to register hardware counters. + +Architectures that have d-cache aliassing issues, such as Sparc and ARM, +should select PERF_USE_VMALLOC in order to avoid these for perf mmap(). diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c index 3d567fe59c7..0d8c85defcd 100644 --- a/tools/perf/util/module.c +++ b/tools/perf/util/module.c @@ -4,6 +4,7 @@ #include "module.h" #include <libelf.h> +#include <libgen.h> #include <gelf.h> #include <elf.h> #include <dirent.h> @@ -409,35 +410,40 @@ out_failure: static int mod_dso__load_module_paths(struct mod_dso *self) { struct utsname uts; - int count = 0, len; + int count = 0, len, err = -1; char *line = NULL; FILE *file; - char *path; + char *dpath, *dir; size_t n; if (uname(&uts) < 0) - goto out_failure; + return err; len = strlen("/lib/modules/"); len += strlen(uts.release); len += strlen("/modules.dep"); - path = calloc(1, len); - if (path == NULL) - goto out_failure; + dpath = calloc(1, len + 1); + if (dpath == NULL) + return err; - strcat(path, "/lib/modules/"); - strcat(path, uts.release); - strcat(path, "/modules.dep"); + strcat(dpath, "/lib/modules/"); + strcat(dpath, uts.release); + strcat(dpath, "/modules.dep"); - file = fopen(path, "r"); - free(path); + file = fopen(dpath, "r"); if (file == NULL) goto out_failure; + dir = dirname(dpath); + if (!dir) + goto out_failure; + strcat(dir, "/"); + while (!feof(file)) { - char *name, *tmp; struct module *module; + char *name, *path, *tmp; + FILE *modfile; int line_len; line_len = getline(&line, &n, file); @@ -445,17 +451,41 @@ static int mod_dso__load_module_paths(struct mod_dso *self) break; if (!line) - goto out_failure; + break; line[--line_len] = '\0'; /* \n */ - path = strtok(line, ":"); + path = strchr(line, ':'); + if (!path) + break; + *path = '\0'; + + path = strdup(line); if (!path) - goto out_failure; + break; + + if (!strstr(path, dir)) { + if (strncmp(path, "kernel/", 7)) + break; + + free(path); + path = calloc(1, strlen(dir) + strlen(line) + 1); + if (!path) + break; + strcat(path, dir); + strcat(path, line); + } + + modfile = fopen(path, "r"); + if (modfile == NULL) + break; + fclose(modfile); name = strdup(path); - name = strtok(name, "/"); + if (!name) + break; + name = strtok(name, "/"); tmp = name; while (tmp) { @@ -463,26 +493,25 @@ static int mod_dso__load_module_paths(struct mod_dso *self) if (tmp) name = tmp; } + name = strsep(&name, "."); + if (!name) + break; - /* Quirk: replace '-' with '_' in sound modules */ + /* Quirk: replace '-' with '_' in all modules */ for (len = strlen(name); len; len--) { if (*(name+len) == '-') *(name+len) = '_'; } module = module__new(name, path); - if (!module) { - fprintf(stderr, "load_module_paths: allocation error\n"); - goto out_failure; - } + if (!module) + break; mod_dso__insert_module(self, module); module->sections = sec_dso__new_dso("sections"); - if (!module->sections) { - fprintf(stderr, "load_module_paths: allocation error\n"); - goto out_failure; - } + if (!module->sections) + break; module->active = mod_dso__load_sections(module); @@ -490,13 +519,20 @@ static int mod_dso__load_module_paths(struct mod_dso *self) count++; } - free(line); - fclose(file); - - return count; + if (feof(file)) + err = count; + else + fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n"); out_failure: - return -1; + if (dpath) + free(dpath); + if (file) + fclose(file); + if (line) + free(line); + + return err; } int mod_dso__load_modules(struct mod_dso *dso) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 13ab4b842d4..8cfb48cbbea 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -165,33 +165,31 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char id_buf[4]; - int sys_dir_fd, fd; + int fd; u64 id; char evt_path[MAXPATHLEN]; + char dir_path[MAXPATHLEN]; if (valid_debugfs_mount(debugfs_path)) return NULL; sys_dir = opendir(debugfs_path); if (!sys_dir) - goto cleanup; - sys_dir_fd = dirfd(sys_dir); + return NULL; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - int dfd = openat(sys_dir_fd, sys_dirent.d_name, - O_RDONLY|O_DIRECTORY), evt_dir_fd; - if (dfd == -1) - continue; - evt_dir = fdopendir(dfd); - if (!evt_dir) { - close(dfd); + + snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, + sys_dirent.d_name); + evt_dir = opendir(dir_path); + if (!evt_dir) continue; - } - evt_dir_fd = dirfd(evt_dir); + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { - snprintf(evt_path, MAXPATHLEN, "%s/id", + + snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dirent.d_name); - fd = openat(evt_dir_fd, evt_path, O_RDONLY); + fd = open(evt_path, O_RDONLY); if (fd < 0) continue; if (read(fd, id_buf, sizeof(id_buf)) < 0) { @@ -225,7 +223,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) closedir(evt_dir); } -cleanup: closedir(sys_dir); return NULL; } @@ -694,7 +691,10 @@ static void store_event_type(const char *orgname) FILE *file; int id; - sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname); + sprintf(filename, "%s/", debugfs_path); + strncat(filename, orgname, strlen(orgname)); + strcat(filename, "/id"); + c = strchr(filename, ':'); if (c) *c = '/'; @@ -761,28 +761,24 @@ static void print_tracepoint_events(void) { DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; - int sys_dir_fd; char evt_path[MAXPATHLEN]; + char dir_path[MAXPATHLEN]; if (valid_debugfs_mount(debugfs_path)) return; sys_dir = opendir(debugfs_path); if (!sys_dir) - goto cleanup; - sys_dir_fd = dirfd(sys_dir); + return; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - int dfd = openat(sys_dir_fd, sys_dirent.d_name, - O_RDONLY|O_DIRECTORY), evt_dir_fd; - if (dfd == -1) - continue; - evt_dir = fdopendir(dfd); - if (!evt_dir) { - close(dfd); + + snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, + sys_dirent.d_name); + evt_dir = opendir(dir_path); + if (!evt_dir) continue; - } - evt_dir_fd = dirfd(evt_dir); + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); @@ -791,8 +787,6 @@ static void print_tracepoint_events(void) } closedir(evt_dir); } - -cleanup: closedir(sys_dir); } diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index a778fd0f4ae..856655d8b0b 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -28,7 +28,7 @@ static u64 turbo_frequency, max_freq; int svg_page_width = 1000; -#define MIN_TEXT_SIZE 0.001 +#define MIN_TEXT_SIZE 0.01 static u64 total_height; static FILE *svgfile; @@ -217,6 +217,18 @@ static char *cpu_model(void) } fclose(file); } + + /* CPU type */ + file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r"); + if (file) { + while (fgets(buf, 255, file)) { + unsigned int freq; + freq = strtoull(buf, NULL, 10); + if (freq > max_freq) + max_freq = freq; + } + fclose(file); + } return cpu_m; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index fd3d9c8e90f..47ea0609a76 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -324,8 +324,7 @@ static inline int elf_sym__is_function(const GElf_Sym *sym) { return elf_sym__type(sym) == STT_FUNC && sym->st_name != 0 && - sym->st_shndx != SHN_UNDEF && - sym->st_size != 0; + sym->st_shndx != SHN_UNDEF; } static inline int elf_sym__is_label(const GElf_Sym *sym) @@ -833,7 +832,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) struct mod_dso *mods = mod_dso__new_dso("modules"); struct module *pos; struct rb_node *next; - int err; + int err, count = 0; err = mod_dso__load_modules(mods); @@ -852,14 +851,16 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) break; next = rb_next(&pos->rb_node); + count += err; } if (err < 0) { mod_dso__delete_modules(mods); mod_dso__delete_self(mods); + return err; } - return err; + return count; } static inline void dso__fill_symbol_holes(struct dso *self) @@ -913,8 +914,15 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, if (vmlinux) { err = dso__load_vmlinux(self, vmlinux, filter, v); - if (err > 0 && use_modules) - err = dso__load_modules(self, filter, v); + if (err > 0 && use_modules) { + int syms = dso__load_modules(self, filter, v); + + if (syms < 0) { + fprintf(stderr, "dso__load_modules failed!\n"); + return syms; + } + err += syms; + } } if (err <= 0) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index f6a8437141c..55c9659a56e 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -618,7 +618,7 @@ static int test_type(enum event_type type, enum event_type expect) } static int test_type_token(enum event_type type, char *token, - enum event_type expect, char *expect_tok) + enum event_type expect, const char *expect_tok) { if (type != expect) { die("Error: expected type %d but read %d", @@ -650,7 +650,7 @@ static int read_expect_type(enum event_type expect, char **tok) return __read_expect_type(expect, tok, 1); } -static int __read_expected(enum event_type expect, char *str, int newline_ok) +static int __read_expected(enum event_type expect, const char *str, int newline_ok) { enum event_type type; char *token; @@ -668,12 +668,12 @@ static int __read_expected(enum event_type expect, char *str, int newline_ok) return 0; } -static int read_expected(enum event_type expect, char *str) +static int read_expected(enum event_type expect, const char *str) { return __read_expected(expect, str, 1); } -static int read_expected_item(enum event_type expect, char *str) +static int read_expected_item(enum event_type expect, const char *str) { return __read_expected(expect, str, 0); } @@ -1968,10 +1968,11 @@ static const struct flag flags[] = { { "NET_TX_SOFTIRQ", 2 }, { "NET_RX_SOFTIRQ", 3 }, { "BLOCK_SOFTIRQ", 4 }, - { "TASKLET_SOFTIRQ", 5 }, - { "SCHED_SOFTIRQ", 6 }, - { "HRTIMER_SOFTIRQ", 7 }, - { "RCU_SOFTIRQ", 8 }, + { "BLOCK_IOPOLL_SOFTIRQ", 5 }, + { "TASKLET_SOFTIRQ", 6 }, + { "SCHED_SOFTIRQ", 7 }, + { "HRTIMER_SOFTIRQ", 8 }, + { "RCU_SOFTIRQ", 9 }, { "HRTIMER_NORESTART", 0 }, { "HRTIMER_RESTART", 1 }, |