From 7752f1b096e13991f20b59fd11ba73da3809d93c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 10 May 2010 13:12:07 -0400 Subject: perf probe: Don't compile CFI related code if elfutils is old Check elfutils version, and if it is old don't compile CFI analysis code. This allows to compile perf with old elfutils. Signed-off-by: Masami Hiramatsu Tested-by: Stephane Eranian Reported-by: Robert Richter Cc: Ingo Molnar LKML-Reference: <20100510171207.26029.97604.stgit@localhost6.localdomain6> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 4 ++++ tools/perf/util/probe-finder.h | 3 +++ 2 files changed, 7 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 562b1443e785..93583eb19cd6 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -668,6 +668,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); if (ret <= 0 || nops == 0) { pf->fb_ops = NULL; +#if _ELFUTILS_PREREQ(0, 142) } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && pf->cfi != NULL) { Dwarf_Frame *frame; @@ -677,6 +678,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) (uintmax_t)pf->addr); return -ENOENT; } +#endif } /* Find each argument */ @@ -956,8 +958,10 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, return -EBADF; } +#if _ELFUTILS_PREREQ(0, 142) /* Get the call frame information from this dwarf */ pf.cfi = dwarf_getcfi(dbg); +#endif off = 0; line_list__init(&pf.lcache); diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 66f1980e3855..e1f61dcd18ff 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -29,6 +29,7 @@ extern int find_line_range(int fd, struct line_range *lr); #include #include +#include struct probe_finder { struct perf_probe_event *pev; /* Target probe event */ @@ -44,7 +45,9 @@ struct probe_finder { struct list_head lcache; /* Line cache for lazy match */ /* For variable searching */ +#if _ELFUTILS_PREREQ(0, 142) Dwarf_CFI *cfi; /* Call Frame Information */ +#endif Dwarf_Op *fb_ops; /* Frame base attribute */ struct perf_probe_arg *pvar; /* Current target variable */ struct kprobe_trace_arg *tvar; /* Current result variable */ -- cgit v1.2.3 From 32ec6acfdcc066313261d0fbe6a966cb1804a7cd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 00:23:14 -0300 Subject: perf tui: Fix build problem with slang <= 2.0.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks the build if it isn't defined. Use the equivalent one that glibc has on features.h. Reported-by: Steven Rostedt Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index ccb7c5bb269e..9338d060ee49 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -1,7 +1,15 @@ #define _GNU_SOURCE #include #undef _GNU_SOURCE - +/* + * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks + * the build if it isn't defined. Use the equivalent one that glibc + * has on features.h. + */ +#include +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG +#endif #include #include #include -- cgit v1.2.3 From 5af52b51f76d8f8dce0e5b2a33c20b2231c8046d Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 18 May 2010 15:00:01 +0200 Subject: perf stat: add perf stat -B to pretty print large numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is hard to read very large numbers so provide an option to perf stat to separate thousands using a separator. The patch leverages the locale support of stdio. You need to set your LC_NUMERIC appropriately, for instance LC_NUMERIC=en_US.UTF8. You need to pass -B to activate this feature. This way existing scripts parsing the output do not need to be changed. Here is an example. $ perf stat noploop 2 noploop for 2 seconds Performance counter stats for 'noploop 2': 1998.347031 task-clock-msecs # 0.998 CPUs 61 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 118 page-faults # 0.000 M/sec 4,138,410,900 cycles # 2070.917 M/sec (scaled from 70.01%) 2,062,650,268 instructions # 0.498 IPC (scaled from 70.01%) 2,057,653,466 branches # 1029.678 M/sec (scaled from 70.01%) 40,267 branch-misses # 0.002 % (scaled from 30.04%) 2,055,961,348 cache-references # 1028.831 M/sec (scaled from 30.03%) 53,725 cache-misses # 0.027 M/sec (scaled from 30.02%) 2.001393933 seconds time elapsed $ perf stat -B noploop 2 noploop for 2 seconds Performance counter stats for 'noploop 2': 1998.297883 task-clock-msecs # 0.998 CPUs 59 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 119 page-faults # 0.000 M/sec 4,131,380,160 cycles # 2067.450 M/sec (scaled from 70.01%) 2,059,096,507 instructions # 0.498 IPC (scaled from 70.01%) 2,054,681,303 branches # 1028.216 M/sec (scaled from 70.01%) 25,650 branch-misses # 0.001 % (scaled from 30.05%) 2,056,283,014 cache-references # 1029.017 M/sec (scaled from 30.03%) 47,097 cache-misses # 0.024 M/sec (scaled from 30.02%) 2.001391016 seconds time elapsed Cc: David S. Miller Cc: Frédéric Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: <4bf28fe8.914ed80a.01ca.fffff5f5@mx.google.com> Signed-off-by: Stephane Eranian Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 3 +++ tools/perf/builtin-stat.c | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 2cab8e8c33d0..909fa766fa1c 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -43,6 +43,9 @@ OPTIONS -c:: scale counter values +-B:: + print large numbers with thousands' separators according to locale + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ff8c413b7e73..9a39ca3c3ac4 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -50,6 +50,7 @@ #include #include +#include static struct perf_event_attr default_attrs[] = { @@ -80,6 +81,8 @@ static pid_t *all_tids = NULL; static int thread_num = 0; static pid_t child_pid = -1; static bool null_run = false; +static bool big_num = false; + static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; @@ -377,7 +380,7 @@ static void nsec_printout(int counter, double avg) { double msecs = avg / 1e6; - fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); + fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { fprintf(stderr, " # %10.3f CPUs ", @@ -389,7 +392,10 @@ static void abs_printout(int counter, double avg) { double total, ratio = 0.0; - fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); + if (big_num) + fprintf(stderr, " %'18.0f %-24s", avg, event_name(counter)); + else + fprintf(stderr, " %18.0f %-24s", avg, event_name(counter)); if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { total = avg_stats(&runtime_cycles_stats); @@ -426,7 +432,7 @@ static void print_counter(int counter) int scaled = event_scaled[counter]; if (scaled == -1) { - fprintf(stderr, " %14s %-24s\n", + fprintf(stderr, " %18s %-24s\n", "", event_name(counter)); return; } @@ -477,7 +483,7 @@ static void print_stat(int argc, const char **argv) print_counter(counter); fprintf(stderr, "\n"); - fprintf(stderr, " %14.9f seconds time elapsed", + fprintf(stderr, " %18.9f seconds time elapsed", avg_stats(&walltime_nsecs_stats)/1e9); if (run_count > 1) { fprintf(stderr, " ( +- %7.3f%% )", @@ -534,6 +540,8 @@ static const struct option options[] = { "repeat command and print average + stddev (max: 100)"), OPT_BOOLEAN('n', "null", &null_run, "null run - dont start any counters"), + OPT_BOOLEAN('B', "big-num", &big_num, + "print large numbers with thousands\' separators"), OPT_END() }; @@ -542,6 +550,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) int status; int i,j; + setlocale(LC_ALL, ""); + argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && target_tid == -1) -- cgit v1.2.3 From a41794cdd7ee94a5199e14f642c26d649d383fa5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 18:29:23 -0300 Subject: perf tools: Remove some unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without the bloated cplus_demangle from binutils, i.e building with: $ make NO_DEMANGLE=1 O=~acme/git/build/perf -j3 -C tools/perf/ install Before: text data bss dec hex filename 471851 29280 4025056 4526187 45106b /home/acme/bin/perf After: [acme@doppio linux-2.6-tip]$ size ~/bin/perf text data bss dec hex filename 446886 29232 4008576 4484694 446e56 /home/acme/bin/perf So its a 5.3% size reduction in code, but the interesting part is in the git diff --stat output: 19 files changed, 20 insertions(+), 1909 deletions(-) If we ever need some of the things we got from git but weren't using, we just have to go to the git repo and get fresh, uptodate source code bits. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 1 + tools/perf/util/abspath.c | 81 -------- tools/perf/util/cache.h | 55 +---- tools/perf/util/config.c | 461 +----------------------------------------- tools/perf/util/exec_cmd.c | 2 +- tools/perf/util/exec_cmd.h | 1 - tools/perf/util/help.c | 30 +-- tools/perf/util/path.c | 202 ------------------ tools/perf/util/quote.c | 433 +-------------------------------------- tools/perf/util/quote.h | 39 ---- tools/perf/util/run-command.c | 90 --------- tools/perf/util/run-command.h | 30 --- tools/perf/util/session.c | 1 + tools/perf/util/sigchain.c | 2 +- tools/perf/util/sigchain.h | 1 - tools/perf/util/strbuf.c | 229 +-------------------- tools/perf/util/strbuf.h | 45 ----- tools/perf/util/util.h | 154 -------------- tools/perf/util/wrapper.c | 72 +------ 19 files changed, 20 insertions(+), 1909 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index cb46c7d0ea99..66b8ecd22cfe 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -25,6 +25,7 @@ #include #include +#include enum write_mode_t { WRITE_FORCE, diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c index a791dd467261..0e76affe9c36 100644 --- a/tools/perf/util/abspath.c +++ b/tools/perf/util/abspath.c @@ -1,86 +1,5 @@ #include "cache.h" -/* - * Do not use this for inspecting *tracked* content. When path is a - * symlink to a directory, we do not want to say it is a directory when - * dealing with tracked content in the working tree. - */ -static int is_directory(const char *path) -{ - struct stat st; - return (!stat(path, &st) && S_ISDIR(st.st_mode)); -} - -/* We allow "recursive" symbolic links. Only within reason, though. */ -#define MAXDEPTH 5 - -const char *make_absolute_path(const char *path) -{ - static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; - char cwd[1024] = ""; - int buf_index = 1, len; - - int depth = MAXDEPTH; - char *last_elem = NULL; - struct stat st; - - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die ("Too long path: %.*s", 60, path); - - while (depth--) { - if (!is_directory(buf)) { - char *last_slash = strrchr(buf, '/'); - if (last_slash) { - *last_slash = '\0'; - last_elem = xstrdup(last_slash + 1); - } else { - last_elem = xstrdup(buf); - *buf = '\0'; - } - } - - if (*buf) { - if (!*cwd && !getcwd(cwd, sizeof(cwd))) - die ("Could not get current working directory"); - - if (chdir(buf)) - die ("Could not switch to '%s'", buf); - } - if (!getcwd(buf, PATH_MAX)) - die ("Could not get current working directory"); - - if (last_elem) { - len = strlen(buf); - - if (len + strlen(last_elem) + 2 > PATH_MAX) - die ("Too long path name: '%s/%s'", - buf, last_elem); - buf[len] = '/'; - strcpy(buf + len + 1, last_elem); - free(last_elem); - last_elem = NULL; - } - - if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { - len = readlink(buf, next_buf, PATH_MAX); - if (len < 0) - die ("Invalid symlink: %s", buf); - if (PATH_MAX <= len) - die("symbolic link too long: %s", buf); - next_buf[len] = '\0'; - buf = next_buf; - buf_index = 1 - buf_index; - next_buf = bufs[buf_index]; - } else - break; - } - - if (*cwd && chdir(cwd)) - die ("Could not change back to '%s'", cwd); - - return buf; -} - static const char *get_pwd_cwd(void) { static char cwd[PATH_MAX + 1]; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 4b9aab7f0405..5eca52595b62 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -13,56 +13,16 @@ #define PERF_DIR_ENVIRONMENT "PERF_DIR" #define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" -#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" -#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY" -#define INDEX_ENVIRONMENT "PERF_INDEX_FILE" -#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE" -#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR" -#define CONFIG_ENVIRONMENT "PERF_CONFIG" #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" -#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES" -#define PERFATTRIBUTES_FILE ".perfattributes" -#define INFOATTRIBUTES_FILE "info/attributes" -#define ATTRIBUTE_MACRO_PREFIX "[attr]" +#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" typedef int (*config_fn_t)(const char *, const char *, void *); extern int perf_default_config(const char *, const char *, void *); -extern int perf_config_from_file(config_fn_t fn, const char *, void *); extern int perf_config(config_fn_t fn, void *); -extern int perf_parse_ulong(const char *, unsigned long *); extern int perf_config_int(const char *, const char *); -extern unsigned long perf_config_ulong(const char *, const char *); -extern int perf_config_bool_or_int(const char *, const char *, int *); extern int perf_config_bool(const char *, const char *); -extern int perf_config_string(const char **, const char *, const char *); -extern int perf_config_set(const char *, const char *); -extern int perf_config_set_multivar(const char *, const char *, const char *, int); -extern int perf_config_rename_section(const char *, const char *); -extern const char *perf_etc_perfconfig(void); -extern int check_repository_format_version(const char *var, const char *value, void *cb); -extern int perf_config_system(void); -extern int perf_config_global(void); extern int config_error_nonbool(const char *); -extern const char *config_exclusive_filename; - -#define MAX_PERFNAME (1000) -extern char perf_default_email[MAX_PERFNAME]; -extern char perf_default_name[MAX_PERFNAME]; -extern int user_ident_explicitly_given; - -extern const char *perf_log_output_encoding; -extern const char *perf_mailmap_file; - -/* IO helper functions */ -extern void maybe_flush_or_die(FILE *, const char *); -extern int copy_fd(int ifd, int ofd); -extern int copy_file(const char *dst, const char *src, int mode); -extern ssize_t write_in_full(int fd, const void *buf, size_t count); -extern void write_or_die(int fd, const void *buf, size_t count); -extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); -extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg); -extern void fsync_or_die(int fd, const char *); /* pager.c */ extern void setup_pager(void); @@ -83,9 +43,6 @@ void setup_browser(void); void exit_browser(bool wait_for_ok); #endif -extern const char *editor_program; -extern const char *excludes_file; - char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); @@ -115,22 +72,12 @@ static inline int is_absolute_path(const char *path) return path[0] == '/'; } -const char *make_absolute_path(const char *path); const char *make_nonrelative_path(const char *path); -const char *make_relative_path(const char *abs, const char *base); -int normalize_path_copy(char *dst, const char *src); -int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -/* perf_mkstemp() - create tmp file honoring TMPDIR variable */ -extern int perf_mkstemp(char *path, size_t len, const char *template); -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) - __attribute__((format (printf, 3, 4))); -extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...) - __attribute__((format (printf, 3, 4))); extern char *perf_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8784649109ce..dabe892d0e53 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -16,7 +16,7 @@ static const char *config_file_name; static int config_linenr; static int config_file_eof; -const char *config_exclusive_filename = NULL; +static const char *config_exclusive_filename; static int get_next_char(void) { @@ -291,19 +291,6 @@ static int perf_parse_long(const char *value, long *ret) return 0; } -int perf_parse_ulong(const char *value, unsigned long *ret) -{ - if (value && *value) { - char *end; - unsigned long val = strtoul(value, &end, 0); - if (!parse_unit_factor(end, &val)) - return 0; - *ret = val; - return 1; - } - return 0; -} - static void die_bad_config(const char *name) { if (config_file_name) @@ -319,15 +306,7 @@ int perf_config_int(const char *name, const char *value) return ret; } -unsigned long perf_config_ulong(const char *name, const char *value) -{ - unsigned long ret; - if (!perf_parse_ulong(value, &ret)) - die_bad_config(name); - return ret; -} - -int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) +static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) { *is_bool = 1; if (!value) @@ -348,14 +327,6 @@ int perf_config_bool(const char *name, const char *value) return !!perf_config_bool_or_int(name, value, &discard); } -int perf_config_string(const char **dest, const char *var, const char *value) -{ - if (!value) - return config_error_nonbool(var); - *dest = strdup(value); - return 0; -} - static int perf_default_core_config(const char *var __used, const char *value __used) { /* Add other config variables here and to Documentation/config.txt. */ @@ -371,7 +342,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used) return 0; } -int perf_config_from_file(config_fn_t fn, const char *filename, void *data) +static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) { int ret; FILE *f = fopen(filename, "r"); @@ -389,7 +360,7 @@ int perf_config_from_file(config_fn_t fn, const char *filename, void *data) return ret; } -const char *perf_etc_perfconfig(void) +static const char *perf_etc_perfconfig(void) { static const char *system_wide; if (!system_wide) @@ -403,12 +374,12 @@ static int perf_env_bool(const char *k, int def) return v ? perf_config_bool(k, v) : def; } -int perf_config_system(void) +static int perf_config_system(void) { return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); } -int perf_config_global(void) +static int perf_config_global(void) { return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); } @@ -449,426 +420,6 @@ int perf_config(config_fn_t fn, void *data) return ret; } -/* - * Find all the stuff for perf_config_set() below. - */ - -#define MAX_MATCHES 512 - -static struct { - int baselen; - char* key; - int do_not_match; - regex_t* value_regex; - int multi_replace; - size_t offset[MAX_MATCHES]; - enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; - int seen; -} store; - -static int matches(const char* key, const char* value) -{ - return !strcmp(key, store.key) && - (store.value_regex == NULL || - (store.do_not_match ^ - !regexec(store.value_regex, value, 0, NULL, 0))); -} - -static int store_aux(const char* key, const char* value, void *cb __used) -{ - int section_len; - const char *ep; - - switch (store.state) { - case KEY_SEEN: - if (matches(key, value)) { - if (store.seen == 1 && store.multi_replace == 0) { - warning("%s has multiple values", key); - } else if (store.seen >= MAX_MATCHES) { - error("too many matches for %s", key); - return 1; - } - - store.offset[store.seen] = ftell(config_file); - store.seen++; - } - break; - case SECTION_SEEN: - /* - * What we are looking for is in store.key (both - * section and var), and its section part is baselen - * long. We found key (again, both section and var). - * We would want to know if this key is in the same - * section as what we are looking for. We already - * know we are in the same section as what should - * hold store.key. - */ - ep = strrchr(key, '.'); - section_len = ep - key; - - if ((section_len != store.baselen) || - memcmp(key, store.key, section_len+1)) { - store.state = SECTION_END_SEEN; - break; - } - - /* - * Do not increment matches: this is no match, but we - * just made sure we are in the desired section. - */ - store.offset[store.seen] = ftell(config_file); - /* fallthru */ - case SECTION_END_SEEN: - case START: - if (matches(key, value)) { - store.offset[store.seen] = ftell(config_file); - store.state = KEY_SEEN; - store.seen++; - } else { - if (strrchr(key, '.') - key == store.baselen && - !strncmp(key, store.key, store.baselen)) { - store.state = SECTION_SEEN; - store.offset[store.seen] = ftell(config_file); - } - } - default: - break; - } - return 0; -} - -static int store_write_section(int fd, const char* key) -{ - const char *dot; - int i, success; - struct strbuf sb = STRBUF_INIT; - - dot = memchr(key, '.', store.baselen); - if (dot) { - strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); - for (i = dot - key + 1; i < store.baselen; i++) { - if (key[i] == '"' || key[i] == '\\') - strbuf_addch(&sb, '\\'); - strbuf_addch(&sb, key[i]); - } - strbuf_addstr(&sb, "\"]\n"); - } else { - strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); - } - - success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len); - strbuf_release(&sb); - - return success; -} - -static int store_write_pair(int fd, const char* key, const char* value) -{ - int i, success; - int length = strlen(key + store.baselen + 1); - const char *quote = ""; - struct strbuf sb = STRBUF_INIT; - - /* - * Check to see if the value needs to be surrounded with a dq pair. - * Note that problematic characters are always backslash-quoted; this - * check is about not losing leading or trailing SP and strings that - * follow beginning-of-comment characters (i.e. ';' and '#') by the - * configuration parser. - */ - if (value[0] == ' ') - quote = "\""; - for (i = 0; value[i]; i++) - if (value[i] == ';' || value[i] == '#') - quote = "\""; - if (i && value[i - 1] == ' ') - quote = "\""; - - strbuf_addf(&sb, "\t%.*s = %s", - length, key + store.baselen + 1, quote); - - for (i = 0; value[i]; i++) - switch (value[i]) { - case '\n': - strbuf_addstr(&sb, "\\n"); - break; - case '\t': - strbuf_addstr(&sb, "\\t"); - break; - case '"': - case '\\': - strbuf_addch(&sb, '\\'); - default: - strbuf_addch(&sb, value[i]); - break; - } - strbuf_addf(&sb, "%s\n", quote); - - success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len); - strbuf_release(&sb); - - return success; -} - -static ssize_t find_beginning_of_line(const char* contents, size_t size, - size_t offset_, int* found_bracket) -{ - size_t equal_offset = size, bracket_offset = size; - ssize_t offset; - -contline: - for (offset = offset_-2; offset > 0 - && contents[offset] != '\n'; offset--) - switch (contents[offset]) { - case '=': equal_offset = offset; break; - case ']': bracket_offset = offset; break; - default: break; - } - if (offset > 0 && contents[offset-1] == '\\') { - offset_ = offset; - goto contline; - } - if (bracket_offset < equal_offset) { - *found_bracket = 1; - offset = bracket_offset+1; - } else - offset++; - - return offset; -} - -int perf_config_set(const char* key, const char* value) -{ - return perf_config_set_multivar(key, value, NULL, 0); -} - -/* - * If value==NULL, unset in (remove from) config, - * if value_regex!=NULL, disregard key/value pairs where value does not match. - * if multi_replace==0, nothing, or only one matching key/value is replaced, - * else all matching key/values (regardless how many) are removed, - * before the new pair is written. - * - * Returns 0 on success. - * - * This function does this: - * - * - it locks the config file by creating ".perf/config.lock" - * - * - it then parses the config using store_aux() as validator to find - * the position on the key/value pair to replace. If it is to be unset, - * it must be found exactly once. - * - * - the config file is mmap()ed and the part before the match (if any) is - * written to the lock file, then the changed part and the rest. - * - * - the config file is removed and the lock file rename()d to it. - * - */ -int perf_config_set_multivar(const char* key, const char* value, - const char* value_regex, int multi_replace) -{ - int i, dot; - int fd = -1, in_fd; - int ret = 0; - char* config_filename; - const char* last_dot = strrchr(key, '.'); - - if (config_exclusive_filename) - config_filename = strdup(config_exclusive_filename); - else - config_filename = perf_pathdup("config"); - - /* - * Since "key" actually contains the section name and the real - * key name separated by a dot, we have to know where the dot is. - */ - - if (last_dot == NULL) { - error("key does not contain a section: %s", key); - ret = 2; - goto out_free; - } - store.baselen = last_dot - key; - - store.multi_replace = multi_replace; - - /* - * Validate the key and while at it, lower case it for matching. - */ - store.key = malloc(strlen(key) + 1); - dot = 0; - for (i = 0; key[i]; i++) { - unsigned char c = key[i]; - if (c == '.') - dot = 1; - /* Leave the extended basename untouched.. */ - if (!dot || i > store.baselen) { - if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) { - error("invalid key: %s", key); - free(store.key); - ret = 1; - goto out_free; - } - c = tolower(c); - } else if (c == '\n') { - error("invalid key (newline): %s", key); - free(store.key); - ret = 1; - goto out_free; - } - store.key[i] = c; - } - store.key[i] = 0; - - /* - * If .perf/config does not exist yet, write a minimal version. - */ - in_fd = open(config_filename, O_RDONLY); - if ( in_fd < 0 ) { - free(store.key); - - if ( ENOENT != errno ) { - error("opening %s: %s", config_filename, - strerror(errno)); - ret = 3; /* same as "invalid config file" */ - goto out_free; - } - /* if nothing to unset, error out */ - if (value == NULL) { - ret = 5; - goto out_free; - } - - store.key = (char*)key; - if (!store_write_section(fd, key) || - !store_write_pair(fd, key, value)) - goto write_err_out; - } else { - struct stat st; - char *contents; - ssize_t contents_sz, copy_begin, copy_end; - int new_line = 0; - - if (value_regex == NULL) - store.value_regex = NULL; - else { - if (value_regex[0] == '!') { - store.do_not_match = 1; - value_regex++; - } else - store.do_not_match = 0; - - store.value_regex = (regex_t*)malloc(sizeof(regex_t)); - if (regcomp(store.value_regex, value_regex, - REG_EXTENDED)) { - error("invalid pattern: %s", value_regex); - free(store.value_regex); - ret = 6; - goto out_free; - } - } - - store.offset[0] = 0; - store.state = START; - store.seen = 0; - - /* - * After this, store.offset will contain the *end* offset - * of the last match, or remain at 0 if no match was found. - * As a side effect, we make sure to transform only a valid - * existing config file. - */ - if (perf_config_from_file(store_aux, config_filename, NULL)) { - error("invalid config file %s", config_filename); - free(store.key); - if (store.value_regex != NULL) { - regfree(store.value_regex); - free(store.value_regex); - } - ret = 3; - goto out_free; - } - - free(store.key); - if (store.value_regex != NULL) { - regfree(store.value_regex); - free(store.value_regex); - } - - /* if nothing to unset, or too many matches, error out */ - if ((store.seen == 0 && value == NULL) || - (store.seen > 1 && multi_replace == 0)) { - ret = 5; - goto out_free; - } - - fstat(in_fd, &st); - contents_sz = xsize_t(st.st_size); - contents = mmap(NULL, contents_sz, PROT_READ, - MAP_PRIVATE, in_fd, 0); - close(in_fd); - - if (store.seen == 0) - store.seen = 1; - - for (i = 0, copy_begin = 0; i < store.seen; i++) { - if (store.offset[i] == 0) { - store.offset[i] = copy_end = contents_sz; - } else if (store.state != KEY_SEEN) { - copy_end = store.offset[i]; - } else - copy_end = find_beginning_of_line( - contents, contents_sz, - store.offset[i]-2, &new_line); - - if (copy_end > 0 && contents[copy_end-1] != '\n') - new_line = 1; - - /* write the first part of the config */ - if (copy_end > copy_begin) { - if (write_in_full(fd, contents + copy_begin, - copy_end - copy_begin) < - copy_end - copy_begin) - goto write_err_out; - if (new_line && - write_in_full(fd, "\n", 1) != 1) - goto write_err_out; - } - copy_begin = store.offset[i]; - } - - /* write the pair (value == NULL means unset) */ - if (value != NULL) { - if (store.state == START) { - if (!store_write_section(fd, key)) - goto write_err_out; - } - if (!store_write_pair(fd, key, value)) - goto write_err_out; - } - - /* write the rest of the config */ - if (copy_begin < contents_sz) - if (write_in_full(fd, contents + copy_begin, - contents_sz - copy_begin) < - contents_sz - copy_begin) - goto write_err_out; - - munmap(contents, contents_sz); - } - - ret = 0; - -out_free: - free(config_filename); - return ret; - -write_err_out: - goto out_free; - -} - /* * Call this to report error for your variable that should not * get a boolean value (i.e. "[my] var" means "true"). diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c index 2745605dba11..c1b3d34e5716 100644 --- a/tools/perf/util/exec_cmd.c +++ b/tools/perf/util/exec_cmd.c @@ -116,7 +116,7 @@ void setup_path(void) strbuf_release(&new_path); } -const char **prepare_perf_cmd(const char **argv) +static const char **prepare_perf_cmd(const char **argv) { int argc; const char **nargv; diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h index 31647ac92ed1..bc4b915963f5 100644 --- a/tools/perf/util/exec_cmd.h +++ b/tools/perf/util/exec_cmd.h @@ -5,7 +5,6 @@ extern void perf_set_argv_exec_path(const char *exec_path); extern const char *perf_extract_argv0_path(const char *path); extern const char *perf_exec_path(void); extern void setup_path(void); -extern const char **prepare_perf_cmd(const char **argv); extern int execv_perf_cmd(const char **argv); /* NULL terminated */ extern int execl_perf_cmd(const char *cmd, ...); extern const char *system_path(const char *path); diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c index fbb00978b2e2..6f2975a00358 100644 --- a/tools/perf/util/help.c +++ b/tools/perf/util/help.c @@ -4,28 +4,6 @@ #include "levenshtein.h" #include "help.h" -/* most GUI terminals set COLUMNS (although some don't export it) */ -static int term_columns(void) -{ - char *col_string = getenv("COLUMNS"); - int n_cols; - - if (col_string && (n_cols = atoi(col_string)) > 0) - return n_cols; - -#ifdef TIOCGWINSZ - { - struct winsize ws; - if (!ioctl(1, TIOCGWINSZ, &ws)) { - if (ws.ws_col) - return ws.ws_col; - } - } -#endif - - return 80; -} - void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) { struct cmdname *ent = malloc(sizeof(*ent) + len + 1); @@ -96,9 +74,13 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest) { int cols = 1, rows; int space = longest + 1; /* min 1 SP between words */ - int max_cols = term_columns() - 1; /* don't print *on* the edge */ + struct winsize win; + int max_cols; int i, j; + get_term_dimensions(&win); + max_cols = win.ws_col - 1; /* don't print *on* the edge */ + if (space < max_cols) cols = max_cols / space; rows = (cmds->cnt + cols - 1) / cols; @@ -324,7 +306,7 @@ const char *help_unknown_cmd(const char *cmd) main_cmds.names[0] = NULL; clean_cmdnames(&main_cmds); - fprintf(stderr, "WARNING: You called a Git program named '%s', " + fprintf(stderr, "WARNING: You called a perf program named '%s', " "which does not exist.\n" "Continuing under the assumption that you meant '%s'\n", cmd, assumed); diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index fd1f2faaade4..b276c187802a 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -54,21 +54,6 @@ static char *cleanup_path(char *path) return path; } -char *mksnpath(char *buf, size_t n, const char *fmt, ...) -{ - va_list args; - unsigned len; - - va_start(args, fmt); - len = vsnprintf(buf, n, fmt, args); - va_end(args); - if (len >= n) { - strlcpy(buf, bad_path, n); - return buf; - } - return cleanup_path(buf); -} - static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) { const char *perf_dir = get_perf_dir(); @@ -89,15 +74,6 @@ bad: return buf; } -char *perf_snpath(char *buf, size_t n, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - (void)perf_vsnpath(buf, n, fmt, args); - va_end(args); - return buf; -} - char *perf_pathdup(const char *fmt, ...) { char path[PATH_MAX]; @@ -143,184 +119,6 @@ char *perf_path(const char *fmt, ...) return cleanup_path(pathname); } - -/* perf_mkstemp() - create tmp file honoring TMPDIR variable */ -int perf_mkstemp(char *path, size_t len, const char *template) -{ - const char *tmp; - size_t n; - - tmp = getenv("TMPDIR"); - if (!tmp) - tmp = "/tmp"; - n = snprintf(path, len, "%s/%s", tmp, template); - if (len <= n) { - errno = ENAMETOOLONG; - return -1; - } - return mkstemp(path); -} - - -const char *make_relative_path(const char *abs_path, const char *base) -{ - static char buf[PATH_MAX + 1]; - int baselen; - - if (!base) - return abs_path; - - baselen = strlen(base); - if (prefixcmp(abs_path, base)) - return abs_path; - if (abs_path[baselen] == '/') - baselen++; - else if (base[baselen - 1] != '/') - return abs_path; - - strcpy(buf, abs_path + baselen); - - return buf; -} - -/* - * It is okay if dst == src, but they should not overlap otherwise. - * - * Performs the following normalizations on src, storing the result in dst: - * - Ensures that components are separated by '/' (Windows only) - * - Squashes sequences of '/'. - * - Removes "." components. - * - Removes ".." components, and the components the precede them. - * Returns failure (non-zero) if a ".." component appears as first path - * component anytime during the normalization. Otherwise, returns success (0). - * - * Note that this function is purely textual. It does not follow symlinks, - * verify the existence of the path, or make any system calls. - */ -int normalize_path_copy(char *dst, const char *src) -{ - char *dst0; - - if (has_dos_drive_prefix(src)) { - *dst++ = *src++; - *dst++ = *src++; - } - dst0 = dst; - - if (is_dir_sep(*src)) { - *dst++ = '/'; - while (is_dir_sep(*src)) - src++; - } - - for (;;) { - char c = *src; - - /* - * A path component that begins with . could be - * special: - * (1) "." and ends -- ignore and terminate. - * (2) "./" -- ignore them, eat slash and continue. - * (3) ".." and ends -- strip one and terminate. - * (4) "../" -- strip one, eat slash and continue. - */ - if (c == '.') { - if (!src[1]) { - /* (1) */ - src++; - } else if (is_dir_sep(src[1])) { - /* (2) */ - src += 2; - while (is_dir_sep(*src)) - src++; - continue; - } else if (src[1] == '.') { - if (!src[2]) { - /* (3) */ - src += 2; - goto up_one; - } else if (is_dir_sep(src[2])) { - /* (4) */ - src += 3; - while (is_dir_sep(*src)) - src++; - goto up_one; - } - } - } - - /* copy up to the next '/', and eat all '/' */ - while ((c = *src++) != '\0' && !is_dir_sep(c)) - *dst++ = c; - if (is_dir_sep(c)) { - *dst++ = '/'; - while (is_dir_sep(c)) - c = *src++; - src--; - } else if (!c) - break; - continue; - - up_one: - /* - * dst0..dst is prefix portion, and dst[-1] is '/'; - * go up one level. - */ - dst--; /* go to trailing '/' */ - if (dst <= dst0) - return -1; - /* Windows: dst[-1] cannot be backslash anymore */ - while (dst0 < dst && dst[-1] != '/') - dst--; - } - *dst = '\0'; - return 0; -} - -/* - * path = Canonical absolute path - * prefix_list = Colon-separated list of absolute paths - * - * Determines, for each path in prefix_list, whether the "prefix" really - * is an ancestor directory of path. Returns the length of the longest - * ancestor directory, excluding any trailing slashes, or -1 if no prefix - * is an ancestor. (Note that this means 0 is returned if prefix_list is - * "/".) "/foo" is not considered an ancestor of "/foobar". Directories - * are not considered to be their own ancestors. path must be in a - * canonical form: empty components, or "." or ".." components are not - * allowed. prefix_list may be null, which is like "". - */ -int longest_ancestor_length(const char *path, const char *prefix_list) -{ - char buf[PATH_MAX+1]; - const char *ceil, *colon; - int len, max_len = -1; - - if (prefix_list == NULL || !strcmp(path, "/")) - return -1; - - for (colon = ceil = prefix_list; *colon; ceil = colon+1) { - for (colon = ceil; *colon && *colon != PATH_SEP; colon++); - len = colon - ceil; - if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil)) - continue; - strlcpy(buf, ceil, len+1); - if (normalize_path_copy(buf, buf) < 0) - continue; - len = strlen(buf); - if (len > 0 && buf[len-1] == '/') - buf[--len] = '\0'; - - if (!strncmp(path, buf, len) && - path[len] == '/' && - len > max_len) { - max_len = len; - } - } - - return max_len; -} - /* strip arbitrary amount of directory separators at end of path */ static inline int chomp_trailing_dir_sep(const char *path, int len) { diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c index 2726fe40eb5d..01f03242b86a 100644 --- a/tools/perf/util/quote.c +++ b/tools/perf/util/quote.c @@ -1,8 +1,6 @@ #include "cache.h" #include "quote.h" -int quote_path_fully = 1; - /* Help to copy the thing properly quoted for the shell safety. * any single quote is replaced with '\'', any exclamation point * is replaced with '\!', and the whole thing is enclosed in a @@ -19,7 +17,7 @@ static inline int need_bs_quote(char c) return (c == '\'' || c == '!'); } -void sq_quote_buf(struct strbuf *dst, const char *src) +static void sq_quote_buf(struct strbuf *dst, const char *src) { char *to_free = NULL; @@ -41,23 +39,6 @@ void sq_quote_buf(struct strbuf *dst, const char *src) free(to_free); } -void sq_quote_print(FILE *stream, const char *src) -{ - char c; - - fputc('\'', stream); - while ((c = *src++)) { - if (need_bs_quote(c)) { - fputs("'\\", stream); - fputc(c, stream); - fputc('\'', stream); - } else { - fputc(c, stream); - } - } - fputc('\'', stream); -} - void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) { int i; @@ -71,415 +52,3 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) die("Too many or long arguments"); } } - -char *sq_dequote_step(char *arg, char **next) -{ - char *dst = arg; - char *src = arg; - char c; - - if (*src != '\'') - return NULL; - for (;;) { - c = *++src; - if (!c) - return NULL; - if (c != '\'') { - *dst++ = c; - continue; - } - /* We stepped out of sq */ - switch (*++src) { - case '\0': - *dst = 0; - if (next) - *next = NULL; - return arg; - case '\\': - c = *++src; - if (need_bs_quote(c) && *++src == '\'') { - *dst++ = c; - continue; - } - /* Fallthrough */ - default: - if (!next || !isspace(*src)) - return NULL; - do { - c = *++src; - } while (isspace(c)); - *dst = 0; - *next = src; - return arg; - } - } -} - -char *sq_dequote(char *arg) -{ - return sq_dequote_step(arg, NULL); -} - -int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc) -{ - char *next = arg; - - if (!*arg) - return 0; - do { - char *dequoted = sq_dequote_step(next, &next); - if (!dequoted) - return -1; - ALLOC_GROW(*argv, *nr + 1, *alloc); - (*argv)[(*nr)++] = dequoted; - } while (next); - - return 0; -} - -/* 1 means: quote as octal - * 0 means: quote as octal if (quote_path_fully) - * -1 means: never quote - * c: quote as "\\c" - */ -#define X8(x) x, x, x, x, x, x, x, x -#define X16(x) X8(x), X8(x) -static signed char const sq_lookup[256] = { - /* 0 1 2 3 4 5 6 7 */ - /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a', - /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1, - /* 0x10 */ X16(1), - /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1, - /* 0x28 */ X16(-1), X16(-1), X16(-1), - /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1, - /* 0x60 */ X16(-1), X8(-1), - /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1, - /* 0x80 */ /* set to 0 */ -}; - -static inline int sq_must_quote(char c) -{ - return sq_lookup[(unsigned char)c] + quote_path_fully > 0; -} - -/* - * Returns the longest prefix not needing a quote up to maxlen if - * positive. - * This stops at the first \0 because it's marked as a character - * needing an escape. - */ -static ssize_t next_quote_pos(const char *s, ssize_t maxlen) -{ - ssize_t len; - - if (maxlen < 0) { - for (len = 0; !sq_must_quote(s[len]); len++); - } else { - for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++); - } - return len; -} - -/* - * C-style name quoting. - * - * (1) if sb and fp are both NULL, inspect the input name and counts the - * number of bytes that are needed to hold c_style quoted version of name, - * counting the double quotes around it but not terminating NUL, and - * returns it. - * However, if name does not need c_style quoting, it returns 0. - * - * (2) if sb or fp are not NULL, it emits the c_style quoted version - * of name, enclosed with double quotes if asked and needed only. - * Return value is the same as in (1). - */ -static size_t quote_c_style_counted(const char *name, ssize_t maxlen, - struct strbuf *sb, FILE *fp, int no_dq) -{ -#define EMIT(c) \ - do { \ - if (sb) strbuf_addch(sb, (c)); \ - if (fp) fputc((c), fp); \ - count++; \ - } while (0) - -#define EMITBUF(s, l) \ - do { \ - int __ret; \ - if (sb) strbuf_add(sb, (s), (l)); \ - if (fp) __ret = fwrite((s), (l), 1, fp); \ - count += (l); \ - } while (0) - - ssize_t len, count = 0; - const char *p = name; - - for (;;) { - int ch; - - len = next_quote_pos(p, maxlen); - if (len == maxlen || !p[len]) - break; - - if (!no_dq && p == name) - EMIT('"'); - - EMITBUF(p, len); - EMIT('\\'); - p += len; - ch = (unsigned char)*p++; - if (sq_lookup[ch] >= ' ') { - EMIT(sq_lookup[ch]); - } else { - EMIT(((ch >> 6) & 03) + '0'); - EMIT(((ch >> 3) & 07) + '0'); - EMIT(((ch >> 0) & 07) + '0'); - } - } - - EMITBUF(p, len); - if (p == name) /* no ending quote needed */ - return 0; - - if (!no_dq) - EMIT('"'); - return count; -} - -size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq) -{ - return quote_c_style_counted(name, -1, sb, fp, nodq); -} - -void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq) -{ - if (quote_c_style(prefix, NULL, NULL, 0) || - quote_c_style(path, NULL, NULL, 0)) { - if (!nodq) - strbuf_addch(sb, '"'); - quote_c_style(prefix, sb, NULL, 1); - quote_c_style(path, sb, NULL, 1); - if (!nodq) - strbuf_addch(sb, '"'); - } else { - strbuf_addstr(sb, prefix); - strbuf_addstr(sb, path); - } -} - -void write_name_quoted(const char *name, FILE *fp, int terminator) -{ - if (terminator) { - quote_c_style(name, NULL, fp, 0); - } else { - fputs(name, fp); - } - fputc(terminator, fp); -} - -void write_name_quotedpfx(const char *pfx, ssize_t pfxlen, - const char *name, FILE *fp, int terminator) -{ - int needquote = 0; - - if (terminator) { - needquote = next_quote_pos(pfx, pfxlen) < pfxlen - || name[next_quote_pos(name, -1)]; - } - if (needquote) { - fputc('"', fp); - quote_c_style_counted(pfx, pfxlen, NULL, fp, 1); - quote_c_style(name, NULL, fp, 1); - fputc('"', fp); - } else { - int ret; - - ret = fwrite(pfx, pfxlen, 1, fp); - fputs(name, fp); - } - fputc(terminator, fp); -} - -/* quote path as relative to the given prefix */ -char *quote_path_relative(const char *in, int len, - struct strbuf *out, const char *prefix) -{ - int needquote; - - if (len < 0) - len = strlen(in); - - /* "../" prefix itself does not need quoting, but "in" might. */ - needquote = (next_quote_pos(in, len) < len); - strbuf_setlen(out, 0); - strbuf_grow(out, len); - - if (needquote) - strbuf_addch(out, '"'); - if (prefix) { - int off = 0; - while (off < len && prefix[off] && prefix[off] == in[off]) - if (prefix[off] == '/') { - prefix += off + 1; - in += off + 1; - len -= off + 1; - off = 0; - } else - off++; - - for (; *prefix; prefix++) - if (*prefix == '/') - strbuf_addstr(out, "../"); - } - - quote_c_style_counted (in, len, out, NULL, 1); - - if (needquote) - strbuf_addch(out, '"'); - if (!out->len) - strbuf_addstr(out, "./"); - - return out->buf; -} - -/* - * C-style name unquoting. - * - * Quoted should point at the opening double quote. - * + Returns 0 if it was able to unquote the string properly, and appends the - * result in the strbuf `sb'. - * + Returns -1 in case of error, and doesn't touch the strbuf. Though note - * that this function will allocate memory in the strbuf, so calling - * strbuf_release is mandatory whichever result unquote_c_style returns. - * - * Updates endp pointer to point at one past the ending double quote if given. - */ -int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp) -{ - size_t oldlen = sb->len, len; - int ch, ac; - - if (*quoted++ != '"') - return -1; - - for (;;) { - len = strcspn(quoted, "\"\\"); - strbuf_add(sb, quoted, len); - quoted += len; - - switch (*quoted++) { - case '"': - if (endp) - *endp = quoted; - return 0; - case '\\': - break; - default: - goto error; - } - - switch ((ch = *quoted++)) { - case 'a': ch = '\a'; break; - case 'b': ch = '\b'; break; - case 'f': ch = '\f'; break; - case 'n': ch = '\n'; break; - case 'r': ch = '\r'; break; - case 't': ch = '\t'; break; - case 'v': ch = '\v'; break; - - case '\\': case '"': - break; /* verbatim */ - - /* octal values with first digit over 4 overflow */ - case '0': case '1': case '2': case '3': - ac = ((ch - '0') << 6); - if ((ch = *quoted++) < '0' || '7' < ch) - goto error; - ac |= ((ch - '0') << 3); - if ((ch = *quoted++) < '0' || '7' < ch) - goto error; - ac |= (ch - '0'); - ch = ac; - break; - default: - goto error; - } - strbuf_addch(sb, ch); - } - - error: - strbuf_setlen(sb, oldlen); - return -1; -} - -/* quoting as a string literal for other languages */ - -void perl_quote_print(FILE *stream, const char *src) -{ - const char sq = '\''; - const char bq = '\\'; - char c; - - fputc(sq, stream); - while ((c = *src++)) { - if (c == sq || c == bq) - fputc(bq, stream); - fputc(c, stream); - } - fputc(sq, stream); -} - -void python_quote_print(FILE *stream, const char *src) -{ - const char sq = '\''; - const char bq = '\\'; - const char nl = '\n'; - char c; - - fputc(sq, stream); - while ((c = *src++)) { - if (c == nl) { - fputc(bq, stream); - fputc('n', stream); - continue; - } - if (c == sq || c == bq) - fputc(bq, stream); - fputc(c, stream); - } - fputc(sq, stream); -} - -void tcl_quote_print(FILE *stream, const char *src) -{ - char c; - - fputc('"', stream); - while ((c = *src++)) { - switch (c) { - case '[': case ']': - case '{': case '}': - case '$': case '\\': case '"': - fputc('\\', stream); - default: - fputc(c, stream); - break; - case '\f': - fputs("\\f", stream); - break; - case '\r': - fputs("\\r", stream); - break; - case '\n': - fputs("\\n", stream); - break; - case '\t': - fputs("\\t", stream); - break; - case '\v': - fputs("\\v", stream); - break; - } - } - fputc('"', stream); -} diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h index b6a019733919..172889ea234f 100644 --- a/tools/perf/util/quote.h +++ b/tools/perf/util/quote.h @@ -22,47 +22,8 @@ * * Note that the above examples leak memory! Remember to free result from * sq_quote() in a real application. - * - * sq_quote_buf() writes to an existing buffer of specified size; it - * will return the number of characters that would have been written - * excluding the final null regardless of the buffer size. */ -extern void sq_quote_print(FILE *stream, const char *src); - -extern void sq_quote_buf(struct strbuf *, const char *src); extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); -/* This unwraps what sq_quote() produces in place, but returns - * NULL if the input does not look like what sq_quote would have - * produced. - */ -extern char *sq_dequote(char *); - -/* - * Same as the above, but can be used to unwrap many arguments in the - * same string separated by space. "next" is changed to point to the - * next argument that should be passed as first parameter. When there - * is no more argument to be dequoted, "next" is updated to point to NULL. - */ -extern char *sq_dequote_step(char *arg, char **next); -extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); - -extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); -extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); -extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); - -extern void write_name_quoted(const char *name, FILE *, int terminator); -extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen, - const char *name, FILE *, int terminator); - -/* quote path as relative to the given prefix */ -char *quote_path_relative(const char *in, int len, - struct strbuf *out, const char *prefix); - -/* quoting as a string literal for other languages */ -extern void perl_quote_print(FILE *stream, const char *src); -extern void python_quote_print(FILE *stream, const char *src); -extern void tcl_quote_print(FILE *stream, const char *src); - #endif /* __PERF_QUOTE_H */ diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c index 2b615acf94d7..da8e9b285f51 100644 --- a/tools/perf/util/run-command.c +++ b/tools/perf/util/run-command.c @@ -212,93 +212,3 @@ int run_command_v_opt(const char **argv, int opt) prepare_run_command_v_opt(&cmd, argv, opt); return run_command(&cmd); } - -int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env) -{ - struct child_process cmd; - prepare_run_command_v_opt(&cmd, argv, opt); - cmd.dir = dir; - cmd.env = env; - return run_command(&cmd); -} - -int start_async(struct async *async) -{ - int pipe_out[2]; - - if (pipe(pipe_out) < 0) - return error("cannot create pipe: %s", strerror(errno)); - async->out = pipe_out[0]; - - /* Flush stdio before fork() to avoid cloning buffers */ - fflush(NULL); - - async->pid = fork(); - if (async->pid < 0) { - error("fork (async) failed: %s", strerror(errno)); - close_pair(pipe_out); - return -1; - } - if (!async->pid) { - close(pipe_out[0]); - exit(!!async->proc(pipe_out[1], async->data)); - } - close(pipe_out[1]); - - return 0; -} - -int finish_async(struct async *async) -{ - int ret = 0; - - if (wait_or_whine(async->pid)) - ret = error("waitpid (async) failed"); - - return ret; -} - -int run_hook(const char *index_file, const char *name, ...) -{ - struct child_process hook; - const char **argv = NULL, *env[2]; - char idx[PATH_MAX]; - va_list args; - int ret; - size_t i = 0, alloc = 0; - - if (access(perf_path("hooks/%s", name), X_OK) < 0) - return 0; - - va_start(args, name); - ALLOC_GROW(argv, i + 1, alloc); - argv[i++] = perf_path("hooks/%s", name); - while (argv[i-1]) { - ALLOC_GROW(argv, i + 1, alloc); - argv[i++] = va_arg(args, const char *); - } - va_end(args); - - memset(&hook, 0, sizeof(hook)); - hook.argv = argv; - hook.no_stdin = 1; - hook.stdout_to_stderr = 1; - if (index_file) { - snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file); - env[0] = idx; - env[1] = NULL; - hook.env = env; - } - - ret = start_command(&hook); - free(argv); - if (ret) { - warning("Could not spawn %s", argv[0]); - return ret; - } - ret = finish_command(&hook); - if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL) - warning("%s exited due to uncaught signal", argv[0]); - - return ret; -} diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h index d79028727ce2..1ef264d5069c 100644 --- a/tools/perf/util/run-command.h +++ b/tools/perf/util/run-command.h @@ -50,39 +50,9 @@ int start_command(struct child_process *); int finish_command(struct child_process *); int run_command(struct child_process *); -extern int run_hook(const char *index_file, const char *name, ...); - #define RUN_COMMAND_NO_STDIN 1 #define RUN_PERF_CMD 2 /*If this is to be perf sub-command */ #define RUN_COMMAND_STDOUT_TO_STDERR 4 int run_command_v_opt(const char **argv, int opt); -/* - * env (the environment) is to be formatted like environ: "VAR=VALUE". - * To unset an environment variable use just "VAR". - */ -int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env); - -/* - * The purpose of the following functions is to feed a pipe by running - * a function asynchronously and providing output that the caller reads. - * - * It is expected that no synchronization and mutual exclusion between - * the caller and the feed function is necessary so that the function - * can run in a thread without interfering with the caller. - */ -struct async { - /* - * proc writes to fd and closes it; - * returns 0 on success, non-zero on failure - */ - int (*proc)(int fd, void *data); - void *data; - int out; /* caller reads from here and closes it */ - pid_t pid; -}; - -int start_async(struct async *async); -int finish_async(struct async *async); - #endif /* __PERF_RUN_COMMAND_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 25bfca4f10f0..e4eaa6d02f57 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "session.h" #include "sort.h" diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c index 1118b99e57d3..ba785e9b1841 100644 --- a/tools/perf/util/sigchain.c +++ b/tools/perf/util/sigchain.c @@ -16,7 +16,7 @@ static void check_signum(int sig) die("BUG: signal out of range: %d", sig); } -int sigchain_push(int sig, sigchain_fun f) +static int sigchain_push(int sig, sigchain_fun f) { struct sigchain_signal *s = signals + sig; check_signum(sig); diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h index 1a53c11265fd..959d64eb5557 100644 --- a/tools/perf/util/sigchain.h +++ b/tools/perf/util/sigchain.h @@ -3,7 +3,6 @@ typedef void (*sigchain_fun)(int); -int sigchain_push(int sig, sigchain_fun f); int sigchain_pop(int sig); void sigchain_push_common(sigchain_fun f); diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 5249d5a1b0c2..92e068517c1a 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -41,16 +41,6 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz) return res; } -void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) -{ - strbuf_release(sb); - sb->buf = buf; - sb->len = len; - sb->alloc = alloc; - strbuf_grow(sb, 0); - sb->buf[sb->len] = '\0'; -} - void strbuf_grow(struct strbuf *sb, size_t extra) { if (sb->len + extra + 1 <= sb->len) @@ -60,94 +50,7 @@ void strbuf_grow(struct strbuf *sb, size_t extra) ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); } -void strbuf_trim(struct strbuf *sb) -{ - char *b = sb->buf; - while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) - sb->len--; - while (sb->len > 0 && isspace(*b)) { - b++; - sb->len--; - } - memmove(sb->buf, b, sb->len); - sb->buf[sb->len] = '\0'; -} -void strbuf_rtrim(struct strbuf *sb) -{ - while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) - sb->len--; - sb->buf[sb->len] = '\0'; -} - -void strbuf_ltrim(struct strbuf *sb) -{ - char *b = sb->buf; - while (sb->len > 0 && isspace(*b)) { - b++; - sb->len--; - } - memmove(sb->buf, b, sb->len); - sb->buf[sb->len] = '\0'; -} - -void strbuf_tolower(struct strbuf *sb) -{ - unsigned int i; - - for (i = 0; i < sb->len; i++) - sb->buf[i] = tolower(sb->buf[i]); -} - -struct strbuf **strbuf_split(const struct strbuf *sb, int delim) -{ - int alloc = 2, pos = 0; - char *n, *p; - struct strbuf **ret; - struct strbuf *t; - - ret = calloc(alloc, sizeof(struct strbuf *)); - p = n = sb->buf; - while (n < sb->buf + sb->len) { - int len; - n = memchr(n, delim, sb->len - (n - sb->buf)); - if (pos + 1 >= alloc) { - alloc = alloc * 2; - ret = realloc(ret, sizeof(struct strbuf *) * alloc); - } - if (!n) - n = sb->buf + sb->len - 1; - len = n - p + 1; - t = malloc(sizeof(struct strbuf)); - strbuf_init(t, len); - strbuf_add(t, p, len); - ret[pos] = t; - ret[++pos] = NULL; - p = ++n; - } - return ret; -} - -void strbuf_list_free(struct strbuf **sbs) -{ - struct strbuf **s = sbs; - - while (*s) { - strbuf_release(*s); - free(*s++); - } - free(sbs); -} - -int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) -{ - int len = a->len < b->len ? a->len: b->len; - int cmp = memcmp(a->buf, b->buf, len); - if (cmp) - return cmp; - return a->len < b->len ? -1: a->len != b->len; -} - -void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, +static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, const void *data, size_t dlen) { if (pos + len < pos) @@ -166,11 +69,6 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, strbuf_setlen(sb, sb->len + dlen - len); } -void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) -{ - strbuf_splice(sb, pos, 0, data, len); -} - void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) { strbuf_splice(sb, pos, len, NULL, 0); @@ -183,13 +81,6 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } -void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) -{ - strbuf_grow(sb, len); - memcpy(sb->buf + sb->len, sb->buf + pos, len); - strbuf_setlen(sb, sb->len + len); -} - void strbuf_addf(struct strbuf *sb, const char *fmt, ...) { int len; @@ -214,57 +105,6 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) strbuf_setlen(sb, sb->len + len); } -void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, - void *context) -{ - for (;;) { - const char *percent; - size_t consumed; - - percent = strchrnul(format, '%'); - strbuf_add(sb, format, percent - format); - if (!*percent) - break; - format = percent + 1; - - consumed = fn(sb, format, context); - if (consumed) - format += consumed; - else - strbuf_addch(sb, '%'); - } -} - -size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, - void *context) -{ - struct strbuf_expand_dict_entry *e = context; - size_t len; - - for (; e->placeholder && (len = strlen(e->placeholder)); e++) { - if (!strncmp(placeholder, e->placeholder, len)) { - if (e->value) - strbuf_addstr(sb, e->value); - return len; - } - } - return 0; -} - -size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) -{ - size_t res; - size_t oldalloc = sb->alloc; - - strbuf_grow(sb, size); - res = fread(sb->buf + sb->len, 1, size, f); - if (res > 0) - strbuf_setlen(sb, sb->len + res); - else if (oldalloc == 0) - strbuf_release(sb); - return res; -} - ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) { size_t oldlen = sb->len; @@ -291,70 +131,3 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) sb->buf[sb->len] = '\0'; return sb->len - oldlen; } - -#define STRBUF_MAXLINK (2*PATH_MAX) - -int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint) -{ - size_t oldalloc = sb->alloc; - - if (hint < 32) - hint = 32; - - while (hint < STRBUF_MAXLINK) { - ssize_t len; - - strbuf_grow(sb, hint); - len = readlink(path, sb->buf, hint); - if (len < 0) { - if (errno != ERANGE) - break; - } else if (len < hint) { - strbuf_setlen(sb, len); - return 0; - } - - /* .. the buffer was too small - try again */ - hint *= 2; - } - if (oldalloc == 0) - strbuf_release(sb); - return -1; -} - -int strbuf_getline(struct strbuf *sb, FILE *fp, int term) -{ - int ch; - - strbuf_grow(sb, 0); - if (feof(fp)) - return EOF; - - strbuf_reset(sb); - while ((ch = fgetc(fp)) != EOF) { - if (ch == term) - break; - strbuf_grow(sb, 1); - sb->buf[sb->len++] = ch; - } - if (ch == EOF && sb->len == 0) - return EOF; - - sb->buf[sb->len] = '\0'; - return 0; -} - -int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint) -{ - int fd, len; - - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - len = strbuf_read(sb, fd, hint); - close(fd); - if (len < 0) - return -1; - - return len; -} diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index a3d121d6c83e..436ac319f6c7 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h @@ -53,12 +53,6 @@ struct strbuf { extern void strbuf_init(struct strbuf *buf, ssize_t hint); extern void strbuf_release(struct strbuf *); extern char *strbuf_detach(struct strbuf *, size_t *); -extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); -static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) { - struct strbuf tmp = *a; - *a = *b; - *b = tmp; -} /*----- strbuf size related -----*/ static inline ssize_t strbuf_avail(const struct strbuf *sb) { @@ -74,17 +68,6 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) { sb->len = len; sb->buf[len] = '\0'; } -#define strbuf_reset(sb) strbuf_setlen(sb, 0) - -/*----- content related -----*/ -extern void strbuf_trim(struct strbuf *); -extern void strbuf_rtrim(struct strbuf *); -extern void strbuf_ltrim(struct strbuf *); -extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); -extern void strbuf_tolower(struct strbuf *); - -extern struct strbuf **strbuf_split(const struct strbuf *, int delim); -extern void strbuf_list_free(struct strbuf **); /*----- add data in your buffer -----*/ static inline void strbuf_addch(struct strbuf *sb, int c) { @@ -93,45 +76,17 @@ static inline void strbuf_addch(struct strbuf *sb, int c) { sb->buf[sb->len] = '\0'; } -extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t); extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); -/* splice pos..pos+len with given data */ -extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, - const void *, size_t); - extern void strbuf_add(struct strbuf *, const void *, size_t); static inline void strbuf_addstr(struct strbuf *sb, const char *s) { strbuf_add(sb, s, strlen(s)); } -static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { - strbuf_add(sb, sb2->buf, sb2->len); -} -extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len); - -typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context); -extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context); -struct strbuf_expand_dict_entry { - const char *placeholder; - const char *value; -}; -extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context); __attribute__((format(printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); -extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); /* XXX: if read fails, any partial read is undone */ extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); -extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint); -extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint); - -extern int strbuf_getline(struct strbuf *, FILE *, int); - -extern void stripspace(struct strbuf *buf, int skip_comments); -extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); - -extern int strbuf_branchname(struct strbuf *sb, const char *name); -extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); #endif /* __PERF_STRBUF_H */ diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0795bf304b19..52118a0c0bad 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -152,7 +152,6 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))) extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); extern int prefixcmp(const char *str, const char *prefix); -extern time_t tm_to_time_t(const struct tm *tm); static inline const char *skip_prefix(const char *str, const char *prefix) { @@ -160,119 +159,6 @@ static inline const char *skip_prefix(const char *str, const char *prefix) return strncmp(str, prefix, len) ? NULL : str + len; } -#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) - -#ifndef PROT_READ -#define PROT_READ 1 -#define PROT_WRITE 2 -#define MAP_PRIVATE 1 -#define MAP_FAILED ((void*)-1) -#endif - -#define mmap git_mmap -#define munmap git_munmap -extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); -extern int git_munmap(void *start, size_t length); - -#else /* NO_MMAP || USE_WIN32_MMAP */ - -#include - -#endif /* NO_MMAP || USE_WIN32_MMAP */ - -#ifdef NO_MMAP - -/* This value must be multiple of (pagesize * 2) */ -#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) - -#else /* NO_MMAP */ - -/* This value must be multiple of (pagesize * 2) */ -#define DEFAULT_PACKED_GIT_WINDOW_SIZE \ - (sizeof(void*) >= 8 \ - ? 1 * 1024 * 1024 * 1024 \ - : 32 * 1024 * 1024) - -#endif /* NO_MMAP */ - -#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT -#define on_disk_bytes(st) ((st).st_size) -#else -#define on_disk_bytes(st) ((st).st_blocks * 512) -#endif - -#define DEFAULT_PACKED_GIT_LIMIT \ - ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) - -#ifdef NO_PREAD -#define pread git_pread -extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); -#endif -/* - * Forward decl that will remind us if its twin in cache.h changes. - * This function is used in compat/pread.c. But we can't include - * cache.h there. - */ -extern ssize_t read_in_full(int fd, void *buf, size_t count); - -#ifdef NO_SETENV -#define setenv gitsetenv -extern int gitsetenv(const char *, const char *, int); -#endif - -#ifdef NO_MKDTEMP -#define mkdtemp gitmkdtemp -extern char *gitmkdtemp(char *); -#endif - -#ifdef NO_UNSETENV -#define unsetenv gitunsetenv -extern void gitunsetenv(const char *); -#endif - -#ifdef NO_STRCASESTR -#define strcasestr gitstrcasestr -extern char *gitstrcasestr(const char *haystack, const char *needle); -#endif - -#ifdef NO_STRLCPY -#define strlcpy gitstrlcpy -extern size_t gitstrlcpy(char *, const char *, size_t); -#endif - -#ifdef NO_STRTOUMAX -#define strtoumax gitstrtoumax -extern uintmax_t gitstrtoumax(const char *, char **, int); -#endif - -#ifdef NO_HSTRERROR -#define hstrerror githstrerror -extern const char *githstrerror(int herror); -#endif - -#ifdef NO_MEMMEM -#define memmem gitmemmem -void *gitmemmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen); -#endif - -#ifdef FREAD_READS_DIRECTORIES -#ifdef fopen -#undef fopen -#endif -#define fopen(a,b) git_fopen(a,b) -extern FILE *git_fopen(const char*, const char*); -#endif - -#ifdef SNPRINTF_RETURNS_BOGUS -#define snprintf git_snprintf -extern int git_snprintf(char *str, size_t maxsize, - const char *format, ...); -#define vsnprintf git_vsnprintf -extern int git_vsnprintf(char *str, size_t maxsize, - const char *format, va_list ap); -#endif - #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2, 1) #define HAVE_STRCHRNUL @@ -294,7 +180,6 @@ static inline char *gitstrchrnul(const char *s, int c) */ extern char *xstrdup(const char *str); extern void *xmalloc(size_t size) __attribute__((weak)); -extern void *xmemdupz(const void *data, size_t len); extern char *xstrndup(const char *str, size_t len); extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); @@ -310,11 +195,6 @@ static inline void *zalloc(size_t size) return calloc(1, size); } -static inline size_t xsize_t(off_t len) -{ - return (size_t)len; -} - static inline int has_extension(const char *filename, const char *ext) { size_t len = strlen(filename); @@ -351,8 +231,6 @@ extern unsigned char sane_ctype[256]; #define isalpha(x) sane_istest(x,GIT_ALPHA) #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) #define isprint(x) sane_istest(x,GIT_PRINT) -#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) -#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) #define tolower(x) sane_case((unsigned char)(x), 0x20) #define toupper(x) sane_case((unsigned char)(x), 0) @@ -363,38 +241,6 @@ static inline int sane_case(int x, int high) return x; } -static inline int strtoul_ui(char const *s, int base, unsigned int *result) -{ - unsigned long ul; - char *p; - - errno = 0; - ul = strtoul(s, &p, base); - if (errno || *p || p == s || (unsigned int) ul != ul) - return -1; - *result = ul; - return 0; -} - -static inline int strtol_i(char const *s, int base, int *result) -{ - long ul; - char *p; - - errno = 0; - ul = strtol(s, &p, base); - if (errno || *p || p == s || (int) ul != ul) - return -1; - *result = ul; - return 0; -} - -#ifdef INTERNAL_QSORT -void git_qsort(void *base, size_t nmemb, size_t size, - int(*compar)(const void *, const void *)); -#define qsort git_qsort -#endif - #ifndef DIR_HAS_BSD_GROUP_SEMANTICS # define FORCE_DIR_SET_GID S_ISGID #else diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c index bf44ca85d23b..c4ced7c1251d 100644 --- a/tools/perf/util/wrapper.c +++ b/tools/perf/util/wrapper.c @@ -48,7 +48,7 @@ void *xmalloc(size_t size) * and returns a pointer to the allocated memory. If the allocation fails, * the program dies. */ -void *xmemdupz(const void *data, size_t len) +static void *xmemdupz(const void *data, size_t len) { char *p = xmalloc(len + 1); memcpy(p, data, len); @@ -78,73 +78,3 @@ void *xrealloc(void *ptr, size_t size) } return ret; } - -/* - * xread() is the same a read(), but it automatically restarts read() - * operations with a recoverable error (EAGAIN and EINTR). xread() - * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. - */ -static ssize_t xread(int fd, void *buf, size_t len) -{ - ssize_t nr; - while (1) { - nr = read(fd, buf, len); - if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) - continue; - return nr; - } -} - -/* - * xwrite() is the same a write(), but it automatically restarts write() - * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT - * GUARANTEE that "len" bytes is written even if the operation is successful. - */ -static ssize_t xwrite(int fd, const void *buf, size_t len) -{ - ssize_t nr; - while (1) { - nr = write(fd, buf, len); - if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) - continue; - return nr; - } -} - -ssize_t read_in_full(int fd, void *buf, size_t count) -{ - char *p = buf; - ssize_t total = 0; - - while (count > 0) { - ssize_t loaded = xread(fd, p, count); - if (loaded <= 0) - return total ? total : loaded; - count -= loaded; - p += loaded; - total += loaded; - } - - return total; -} - -ssize_t write_in_full(int fd, const void *buf, size_t count) -{ - const char *p = buf; - ssize_t total = 0; - - while (count > 0) { - ssize_t written = xwrite(fd, p, count); - if (written < 0) - return -1; - if (!written) { - errno = ENOSPC; - return -1; - } - count -= written; - p += written; - total += written; - } - - return total; -} -- cgit v1.2.3 From b448c4b613542c16ad66042017946e68da4e422b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 23:04:28 -0300 Subject: perf probe: Fix some error exit paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That could leave filedescriptors open and leak memory. Also stop using xmalloc, use malloc and handle results just like other error cases in the same routine that used it. Cc: Frédéric Weisbecker Cc: Masami Hiramatsu Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 93583eb19cd6..d964cb199c67 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -743,32 +743,36 @@ static int find_lazy_match_lines(struct list_head *head, const char *fname, const char *pat) { char *fbuf, *p1, *p2; - int fd, ret, line, nlines = 0; + int fd, line, nlines = -1; struct stat st; fd = open(fname, O_RDONLY); if (fd < 0) { pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); - return fd; + return -errno; } - ret = fstat(fd, &st); - if (ret < 0) { + if (fstat(fd, &st) < 0) { pr_warning("Failed to get the size of %s: %s\n", fname, strerror(errno)); - return ret; + nlines = -errno; + goto out_close; } - fbuf = xmalloc(st.st_size + 2); - ret = read(fd, fbuf, st.st_size); - if (ret < 0) { + + nlines = -ENOMEM; + fbuf = malloc(st.st_size + 2); + if (fbuf == NULL) + goto out_close; + if (read(fd, fbuf, st.st_size) < 0) { pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); - return ret; + nlines = -errno; + goto out_free_fbuf; } - close(fd); fbuf[st.st_size] = '\n'; /* Dummy line */ fbuf[st.st_size + 1] = '\0'; p1 = fbuf; line = 1; + nlines = 0; while ((p2 = strchr(p1, '\n')) != NULL) { *p2 = '\0'; if (strlazymatch(p1, pat)) { @@ -778,7 +782,10 @@ static int find_lazy_match_lines(struct list_head *head, line++; p1 = p2 + 1; } +out_free_fbuf: free(fbuf); +out_close: + close(fd); return nlines; } @@ -955,6 +962,8 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, if (!dbg) { pr_warning("No dwarf info found in the vmlinux - " "please rebuild with CONFIG_DEBUG_INFO=y.\n"); + free(pf.tevs); + *tevs = NULL; return -EBADF; } -- cgit v1.2.3 From 8a7ddad8e756a72906851fdd5a6e149cbb056e0d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 22:57:27 -0300 Subject: perf probe: Don't call die() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Functions that were calling xzalloc also returned -1 when, for other reasons, it could fail, and the calleds are coping with failures, so stop using die() and xzalloc(). Cc: Frédéric Weisbecker Cc: Masami Hiramatsu Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 61c6d70732c9..e4a4da32a568 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -65,8 +65,10 @@ static int parse_probe_event(const char *str) int ret; pr_debug("probe-definition(%d): %s\n", params.nevents, str); - if (++params.nevents == MAX_PROBES) - die("Too many probes (> %d) are specified.", MAX_PROBES); + if (++params.nevents == MAX_PROBES) { + pr_err("Too many probes (> %d) were specified.", MAX_PROBES); + return -1; + } /* Parse a perf-probe command into event */ ret = parse_perf_probe_command(str, pev); @@ -84,7 +86,9 @@ static int parse_probe_event_argv(int argc, const char **argv) len = 0; for (i = 0; i < argc; i++) len += strlen(argv[i]) + 1; - buf = xzalloc(len + 1); + buf = zalloc(len + 1); + if (buf == NULL) + return -ENOMEM; len = 0; for (i = 0; i < argc; i++) len += sprintf(&buf[len], "%s ", argv[i]); -- cgit v1.2.3 From 151f85a471d29fc81f70348143d009a729901bc0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 18:54:30 -0300 Subject: perf tools: remove xstrndup, xmalloc, xzalloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the functions that call this can handle the equivalent, non panic'ing wrapped routines. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/exec_cmd.c | 4 ++-- tools/perf/util/path.c | 2 +- tools/perf/util/util.h | 8 -------- tools/perf/util/wrapper.c | 40 ---------------------------------------- 4 files changed, 3 insertions(+), 51 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c index c1b3d34e5716..67eeff571568 100644 --- a/tools/perf/util/exec_cmd.c +++ b/tools/perf/util/exec_cmd.c @@ -53,8 +53,8 @@ const char *perf_extract_argv0_path(const char *argv0) slash--; if (slash >= argv0) { - argv0_path = xstrndup(argv0, slash - argv0); - return slash + 1; + argv0_path = strndup(argv0, slash - argv0); + return argv0_path ? slash + 1 : NULL; } return argv0; diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index b276c187802a..58a470d036dd 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -152,5 +152,5 @@ char *strip_path_suffix(const char *path, const char *suffix) if (path_len && !is_dir_sep(path[path_len - 1])) return NULL; - return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); + return strndup(path, chomp_trailing_dir_sep(path, path_len)); } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 52118a0c0bad..45b9655f3a5c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -179,16 +179,8 @@ static inline char *gitstrchrnul(const char *s, int c) * Wrappers: */ extern char *xstrdup(const char *str); -extern void *xmalloc(size_t size) __attribute__((weak)); -extern char *xstrndup(const char *str, size_t len); extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); -static inline void *xzalloc(size_t size) -{ - void *buf = xmalloc(size); - - return memset(buf, 0, size); -} static inline void *zalloc(size_t size) { diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c index c4ced7c1251d..73e900edb5a2 100644 --- a/tools/perf/util/wrapper.c +++ b/tools/perf/util/wrapper.c @@ -23,46 +23,6 @@ char *xstrdup(const char *str) return ret; } -void *xmalloc(size_t size) -{ - void *ret = malloc(size); - if (!ret && !size) - ret = malloc(1); - if (!ret) { - release_pack_memory(size, -1); - ret = malloc(size); - if (!ret && !size) - ret = malloc(1); - if (!ret) - die("Out of memory, malloc failed"); - } -#ifdef XMALLOC_POISON - memset(ret, 0xA5, size); -#endif - return ret; -} - -/* - * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of - * "data" to the allocated memory, zero terminates the allocated memory, - * and returns a pointer to the allocated memory. If the allocation fails, - * the program dies. - */ -static void *xmemdupz(const void *data, size_t len) -{ - char *p = xmalloc(len + 1); - memcpy(p, data, len); - p[len] = '\0'; - return p; -} - -char *xstrndup(const char *str, size_t len) -{ - char *p = memchr(str, '\0', len); - - return xmemdupz(str, p ? (size_t)(p - str) : len); -} - void *xrealloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); -- cgit v1.2.3 From f6e1467d8303a397ce40bcfb5f72f97d3ebc768f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 May 2010 11:13:02 -0300 Subject: perf symbols: Don't try to read the build-id twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In __dsos__read_build_ids if the dso already had its build-id read, don't try again. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a06131f6259a..87d9b1b8b6bb 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1131,6 +1131,10 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) list_for_each_entry(pos, head, node) { if (with_hits && !pos->hit) continue; + if (pos->has_build_id) { + have_build_id = true; + continue; + } if (filename__read_build_id(pos->long_name, pos->build_id, sizeof(pos->build_id)) > 0) { have_build_id = true; -- cgit v1.2.3 From f869097e884d8cb65b2bb7831ca57b7dffb66fdd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 May 2010 13:41:23 -0300 Subject: perf session: Make read_build_id routines look at the host_machine too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The changes made to support host and guest machines in a session, that started when the 'perf kvm' tool was introduced ended up introducing a bug where the host_machine was not having its DSOs traversed for build-id processing. Fix it by moving some methods to the right classes and considering the host_machine when processing build-ids. Reported-by: Tom Zanussi Reported-by: Stephane Eranian Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 84 +++++++++++++++++++++++++++++------------------ tools/perf/util/session.c | 7 ++++ tools/perf/util/session.h | 8 ++--- tools/perf/util/symbol.c | 9 +++-- tools/perf/util/symbol.h | 1 + 5 files changed, 69 insertions(+), 40 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8847bec64c54..1f62435f96c2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -221,29 +221,38 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, return 0; } +static int machine__write_buildid_table(struct machine *self, int fd) +{ + int err; + u16 kmisc = PERF_RECORD_MISC_KERNEL, + umisc = PERF_RECORD_MISC_USER; + + if (!machine__is_host(self)) { + kmisc = PERF_RECORD_MISC_GUEST_KERNEL; + umisc = PERF_RECORD_MISC_GUEST_USER; + } + + err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, + kmisc, fd); + if (err == 0) + err = __dsos__write_buildid_table(&self->user_dsos, + self->pid, umisc, fd); + return err; +} + static int dsos__write_buildid_table(struct perf_header *header, int fd) { struct perf_session *session = container_of(header, struct perf_session, header); struct rb_node *nd; - int err = 0; - u16 kmisc, umisc; + int err = machine__write_buildid_table(&session->host_machine, fd); + + if (err) + return err; for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - if (machine__is_host(pos)) { - kmisc = PERF_RECORD_MISC_KERNEL; - umisc = PERF_RECORD_MISC_USER; - } else { - kmisc = PERF_RECORD_MISC_GUEST_KERNEL; - umisc = PERF_RECORD_MISC_GUEST_USER; - } - - err = __dsos__write_buildid_table(&pos->kernel_dsos, pos->pid, - kmisc, fd); - if (err == 0) - err = __dsos__write_buildid_table(&pos->user_dsos, - pos->pid, umisc, fd); + err = machine__write_buildid_table(pos, fd); if (err) break; } @@ -363,12 +372,17 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) return err; } -static int dsos__cache_build_ids(struct perf_header *self) +static int machine__cache_build_ids(struct machine *self, const char *debugdir) +{ + int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); + ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); + return ret; +} + +static int perf_session__cache_build_ids(struct perf_session *self) { - struct perf_session *session = container_of(self, - struct perf_session, header); struct rb_node *nd; - int ret = 0; + int ret; char debugdir[PATH_MAX]; snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), @@ -377,25 +391,30 @@ static int dsos__cache_build_ids(struct perf_header *self) if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) return -1; - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + ret = machine__cache_build_ids(&self->host_machine, debugdir); + + for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= __dsos__cache_build_ids(&pos->kernel_dsos, debugdir); - ret |= __dsos__cache_build_ids(&pos->user_dsos, debugdir); + ret |= machine__cache_build_ids(pos, debugdir); } return ret ? -1 : 0; } -static bool dsos__read_build_ids(struct perf_header *self, bool with_hits) +static bool machine__read_build_ids(struct machine *self, bool with_hits) +{ + bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); + ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); + return ret; +} + +static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) { - bool ret = false; - struct perf_session *session = container_of(self, - struct perf_session, header); struct rb_node *nd; + bool ret = machine__read_build_ids(&self->host_machine, with_hits); - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= __dsos__read_build_ids(&pos->kernel_dsos, with_hits); - ret |= __dsos__read_build_ids(&pos->user_dsos, with_hits); + ret |= machine__read_build_ids(pos, with_hits); } return ret; @@ -404,12 +423,14 @@ static bool dsos__read_build_ids(struct perf_header *self, bool with_hits) static int perf_header__adds_write(struct perf_header *self, int fd) { int nr_sections; + struct perf_session *session; struct perf_file_section *feat_sec; int sec_size; u64 sec_start; int idx = 0, err; - if (dsos__read_build_ids(self, true)) + session = container_of(self, struct perf_session, header); + if (perf_session__read_build_ids(session, true)) perf_header__set_feat(self, HEADER_BUILD_ID); nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); @@ -450,7 +471,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) } buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; - dsos__cache_build_ids(self); + perf_session__cache_build_ids(session); } lseek(fd, sec_start, SEEK_SET); @@ -490,7 +511,6 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) lseek(fd, sizeof(f_header), SEEK_SET); - for (i = 0; i < self->attrs; i++) { attr = self->attr[i]; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e4eaa6d02f57..8f83a1835766 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -895,3 +895,10 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) __dsos__fprintf(&self->host_machine.user_dsos, fp) + machines__fprintf_dsos(&self->machines, fp); } + +size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, + bool with_hits) +{ + size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); + return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index e7fce486ebe2..55c6881b218d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -132,12 +132,8 @@ void perf_session__process_machines(struct perf_session *self, size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); -static inline -size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, - bool with_hits) -{ - return machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); -} +size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, + FILE *fp, bool with_hits); static inline size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 87d9b1b8b6bb..96bff0e54863 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1937,6 +1937,12 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, return ret; } +size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) +{ + return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + + __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); +} + size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) { struct rb_node *nd; @@ -1944,8 +1950,7 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_ for (nd = rb_first(self); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += __dsos__fprintf_buildid(&pos->kernel_dsos, fp, with_hits); - ret += __dsos__fprintf_buildid(&pos->user_dsos, fp, with_hits); + ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); } return ret; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 032469e41876..5d25b5eb1456 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -170,6 +170,7 @@ int machine__load_vmlinux_path(struct machine *self, enum map_type type, size_t __dsos__fprintf(struct list_head *head, FILE *fp); +size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits); size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp); size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits); -- cgit v1.2.3 From cbb5cf7ff6b298beacfe23db3386335b0b9c0a2d Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Tue, 4 May 2010 23:02:10 -0500 Subject: perf: Use read() instead of lseek() in trace_event_read.c:skip() This is a small fix for a problem affecting live-mode, introduced recently: root@tropicana:~# perf trace rwtop perf trace started with Perl script /root/libexec/perf-core/scripts/perl/rwtop.pl Fatal: did not read header event commit d00a47cce569a3e660a8c9de5d57af28d6a9f0f7 added a skip() function to skip over e.g. header_page, but this doesn't work for live mode. This patch re-implements skip() to use read() instead of lseek() to fix that. Signed-off-by: Tom Zanussi Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras LKML-Reference: <1273032130.6383.28.camel@tropicana> Signed-off-by: Frederic Weisbecker --- tools/perf/util/trace-event-read.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index cb54cd002f49..f55cc3a765a1 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -53,12 +53,6 @@ static unsigned long page_size; static ssize_t calc_data_size; static bool repipe; -/* If it fails, the next read will report it */ -static void skip(int size) -{ - lseek(input_fd, size, SEEK_CUR); -} - static int do_read(int fd, void *buf, int size) { int rsize = size; @@ -98,6 +92,19 @@ static int read_or_die(void *data, int size) return r; } +/* If it fails, the next read will report it */ +static void skip(int size) +{ + char buf[BUFSIZ]; + int r; + + while (size) { + r = size > BUFSIZ ? BUFSIZ : size; + read_or_die(buf, r); + size -= r; + }; +} + static unsigned int read4(void) { unsigned int data; -- cgit v1.2.3 From 85cb68b27c428d477169f3aa46c72dba103a17bd Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 20 May 2010 10:34:59 +0200 Subject: perf: Fix unaligned accesses while fetching trace values Accessing trace values of an 8 size may end up in a segfault on archs that can't deal with misaligned access, which is the case for sparc 64. This is because PERF_SAMPLE_RAW are aligned to 4 and not to 8. Fix this on the macros that get the values of 8 size. This fixes segfaults on perf tools in sparc 64. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Steven Rostedt Cc: Tom Zanussi Cc: Masami Hiramatsu Cc: David Miller --- tools/perf/util/trace-event.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 406d452956db..b3e86b1e4444 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -233,7 +233,12 @@ static inline unsigned long long __data2host8(unsigned long long data) #define data2host2(ptr) __data2host2(*(unsigned short *)ptr) #define data2host4(ptr) __data2host4(*(unsigned int *)ptr) -#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr) +#define data2host8(ptr) ({ \ + unsigned long long __val; \ + \ + memcpy(&__val, (ptr), sizeof(unsigned long long)); \ + __data2host8(__val); \ +}) extern int header_page_ts_offset; extern int header_page_ts_size; -- cgit v1.2.3 From 17930b405e0ecdc8ecc4d336377a92950e2de76a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 May 2010 16:03:51 -0300 Subject: perf TUI: Make 'space' be an alias to 'PgDn' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like if one is using the stdio based pager, or more/less, for that matter. Suggested-by: Peter Zijlstra Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 9338d060ee49..051022eb5f43 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -383,6 +383,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title, newtFormAddHotKey(self->form, NEWT_KEY_DOWN); newtFormAddHotKey(self->form, NEWT_KEY_PGUP); newtFormAddHotKey(self->form, NEWT_KEY_PGDN); + newtFormAddHotKey(self->form, ' '); newtFormAddHotKey(self->form, NEWT_KEY_HOME); newtFormAddHotKey(self->form, NEWT_KEY_END); @@ -419,6 +420,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title, } break; case NEWT_KEY_PGDN: + case ' ': if (self->first_visible_entry_idx + self->height > self->nr_entries - 1) break; -- cgit v1.2.3 From b36f19d572151abb987ce308a3e066b977a2146f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 May 2010 12:15:33 -0300 Subject: perf annotate: Use build-ids to find the right DSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were still using the pathname found on the MMAP event, that could not be the one we used when recording, so use the build-id cache for that, only falling back to use the pathname in the MMAP event if no build-ids are available. With this we now also are able to do secure, seamless offline annotation. Example: [root@doppio linux-2.6-tip]# perf report -g none -v 2> /dev/null | head -10 8.12% Xorg /usr/lib64/libpixman-1.so.0.14.0 0x0000000000026d02 B [.] pixman_rasterize_edges 4.68% firefox /usr/lib64/xulrunner-1.9.1/libxul.so 0x00000000005dbdba B [.] 0x000000005dbdba 3.70% swapper /lib/modules/2.6.34-rc6/build/vmlinux 0xffffffff81022cea ! [k] read_hpet 2.96% init /lib/modules/2.6.34-rc6/build/vmlinux 0xffffffff81022cea ! [k] read_hpet 2.73% swapper /lib/modules/2.6.34-rc6/build/vmlinux 0xffffffff8100a738 ! [k] mwait_idle_with_hints [root@doppio linux-2.6-tip]# perf annotate -v pixman_rasterize_edges 2>&1 | grep Executing Executing: objdump --start-address=0x000000371ce26670 --stop-address=0x000000371ce2709f -dS /root/.debug/.build-id/bd/6ac5199137aaeb279f864717d8d061477466c1|grep -v /root/.debug/.build-id/bd/6ac5199137aaeb279f864717d8d061477466c1|expand [root@doppio linux-2.6-tip]# perf buildid-list | grep libpixman-1.so.0.14.0 bd6ac5199137aaeb279f864717d8d061477466c1 /usr/lib64/libpixman-1.so.0.14.0 [root@doppio linux-2.6-tip]# Reported-by: Stephane Eranian Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 22 ++++++++++++++++++++++ tools/perf/util/build-id.h | 2 ++ tools/perf/util/callchain.c | 1 + tools/perf/util/callchain.h | 1 - tools/perf/util/hist.c | 34 ++++++++++++++++++++++++++-------- tools/perf/util/symbol.c | 12 +++--------- 6 files changed, 54 insertions(+), 18 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0f60a3906808..70c5cf87d020 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -6,6 +6,8 @@ * Copyright (C) 2009, 2010 Red Hat Inc. * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo */ +#include "util.h" +#include #include "build-id.h" #include "event.h" #include "symbol.h" @@ -37,3 +39,23 @@ struct perf_event_ops build_id__mark_dso_hit_ops = { .mmap = event__process_mmap, .fork = event__process_task, }; + +char *dso__build_id_filename(struct dso *self, char *bf, size_t size) +{ + char build_id_hex[BUILD_ID_SIZE * 2 + 1]; + const char *home; + + if (!self->has_build_id) + return NULL; + + build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); + home = getenv("HOME"); + if (bf == NULL) { + if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home, + DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0) + return NULL; + } else + snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home, + DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2); + return bf; +} diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 1d981d63cf9a..5dafb00eaa06 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -5,4 +5,6 @@ extern struct perf_event_ops build_id__mark_dso_hit_ops; +char *dso__build_id_filename(struct dso *self, char *bf, size_t size); + #endif diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 21a52e0a4435..62b69ad4aa73 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -15,6 +15,7 @@ #include #include +#include "util.h" #include "callchain.h" bool ip_callchain__valid(struct ip_callchain *chain, event_t *event) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 1cba1f5504e7..1ca73e4a2723 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -5,7 +5,6 @@ #include #include #include "event.h" -#include "util.h" #include "symbol.h" enum chain_mode { diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 9a71c94f057a..739c39fd0ade 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1,3 +1,4 @@ +#include "build-id.h" #include "util.h" #include "hist.h" #include "session.h" @@ -988,22 +989,35 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) struct symbol *sym = self->ms.sym; struct map *map = self->ms.map; struct dso *dso = map->dso; - const char *filename = dso->long_name; + char *filename = dso__build_id_filename(dso, NULL, 0); char command[PATH_MAX * 2]; FILE *file; + int err = -1; u64 len; - if (!filename) - return -1; + if (filename == NULL) { + if (dso->has_build_id) { + pr_err("Can't annotate %s: not enough memory\n", + sym->name); + return -1; + } + /* + * If we don't have build-ids, well, lets hope that this + * DSO is the same as when 'perf record' ran. + */ + filename = dso->long_name; + } if (dso->origin == DSO__ORIG_KERNEL) { - if (dso->annotate_warned) - return 0; + if (dso->annotate_warned) { + err = 0; + goto out_free_filename; + } dso->annotate_warned = 1; pr_err("Can't annotate %s: No vmlinux file was found in the " "path:\n", sym->name); vmlinux_path__fprintf(stderr); - return -1; + goto out_free_filename; } pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, @@ -1025,14 +1039,18 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) file = popen(command, "r"); if (!file) - return -1; + goto out_free_filename; while (!feof(file)) if (hist_entry__parse_objdump_line(self, file, head) < 0) break; pclose(file); - return 0; + err = 0; +out_free_filename: + if (dso->has_build_id) + free(filename); + return err; } void hists__inc_nr_events(struct hists *self, u32 type) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 96bff0e54863..aaa51ba147df 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -11,6 +11,7 @@ #include #include #include +#include "build-id.h" #include "symbol.h" #include "strlist.h" @@ -1293,7 +1294,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) int size = PATH_MAX; char *name; u8 build_id[BUILD_ID_SIZE]; - char build_id_hex[BUILD_ID_SIZE * 2 + 1]; int ret = -1; int fd; struct machine *machine; @@ -1325,15 +1325,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) } self->origin = DSO__ORIG_BUILD_ID_CACHE; - - if (self->has_build_id) { - build_id__sprintf(self->build_id, sizeof(self->build_id), - build_id_hex); - snprintf(name, size, "%s/%s/.build-id/%.2s/%s", - getenv("HOME"), DEBUG_CACHE_DIR, - build_id_hex, build_id_hex + 2); + if (dso__build_id_filename(self, name, size) != NULL) goto open_file; - } more: do { self->origin++; @@ -1349,6 +1342,7 @@ more: case DSO__ORIG_BUILDID: if (filename__read_build_id(self->long_name, build_id, sizeof(build_id))) { + char build_id_hex[BUILD_ID_SIZE * 2 + 1]; build_id__sprintf(build_id, sizeof(build_id), build_id_hex); snprintf(name, size, -- cgit v1.2.3 From ef365cefbc53d8674a18520a1d4c2e5590127299 Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Tue, 18 May 2010 17:52:40 -0500 Subject: perf record: remove unneeded gettimeofday() call Perf record repeatedly calls gettimeofday() which adds noise to the performance measurements. Since gettimeofday() is only used for the error printf, delete it. Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <20100518225240.GC25589@sgi.com> Signed-off-by: Russ Anderson Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 66b8ecd22cfe..e67226981834 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -65,9 +65,6 @@ static bool multiplex = false; static int multiplex_fd = -1; static long samples = 0; -static struct timeval last_read; -static struct timeval this_read; - static u64 bytes_written = 0; static struct pollfd *event_array; @@ -147,8 +144,6 @@ static void mmap_read(struct mmap_data *md) void *buf; int diff; - gettimeofday(&this_read, NULL); - /* * If we're further behind than half the buffer, there's a chance * the writer will bite our tail and mess up the samples under us. @@ -159,23 +154,13 @@ static void mmap_read(struct mmap_data *md) */ diff = head - old; if (diff < 0) { - struct timeval iv; - unsigned long msecs; - - timersub(&this_read, &last_read, &iv); - msecs = iv.tv_sec*1000 + iv.tv_usec/1000; - - fprintf(stderr, "WARNING: failed to keep up with mmap data." - " Last read %lu msecs ago.\n", msecs); - + fprintf(stderr, "WARNING: failed to keep up with mmap data\n"); /* * head points to a known good entry, start there. */ old = head; } - last_read = this_read; - if (old != head) samples++; -- cgit v1.2.3 From 5d06e6915b1b76653e6fe3369b0b18fdbf75f0a5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 May 2010 22:01:10 -0300 Subject: perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the same scheme as for git's/perf's pager setup, i.e. if one doesn't want to, on a newt enabled perf binary, to disable the TUI for 'perf report', its just a matter of doing: [root@doppio linux-2.6-tip]# printf "[tui]\n\nreport = off\n" > /root/.perfconfig [root@doppio linux-2.6-tip]# cat /root/.perfconfig [tui] report = off [root@doppio linux-2.6-tip]# System wide settings are also possible, by editing /etc/perfconfig, etc, i.e. the git machinery for config files applies to perf as well, so when in doubt where to put your settings, consult the git documentation, if it fails, please let us know. Suggested-by: Ingo Molnar Discussed-with: Stephane Eranian Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 8 ++++---- tools/perf/perf.c | 25 +++++++++++++++++++++++-- tools/perf/util/cache.h | 2 +- tools/perf/util/newt.c | 9 ++++++--- 4 files changed, 34 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1d3c1003b43a..a7b8760e401c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, * so we don't allocated the extra space needed because the stdio * code will not use it. */ - if (use_browser) + if (use_browser > 0) err = hist_entry__inc_addr_samples(he, al->addr); out_free_syms: free(syms); @@ -330,7 +330,7 @@ static int __cmd_report(void) hists = rb_entry(next, struct hists, rb_node); hists__collapse_resort(hists); hists__output_resort(hists); - if (use_browser) + if (use_browser > 0) hists__browse(hists, help, input_name); else { const char *evname = NULL; @@ -347,7 +347,7 @@ static int __cmd_report(void) next = rb_next(&hists->rb_node); } - if (!use_browser && sort_order == default_sort_order && + if (use_browser <= 0 && sort_order == default_sort_order && parent_pattern == default_parent_pattern) { fprintf(stdout, "#\n# (%s)\n#\n", help); @@ -491,7 +491,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) * so don't allocate extra space that won't be used in the stdio * implementation. */ - if (use_browser) + if (use_browser > 0) symbol_conf.priv_size = sizeof(struct sym_priv); if (symbol__init() < 0) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 08e0e5d2b50e..6e4871191138 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -15,15 +15,15 @@ #include "util/parse-events.h" #include "util/debugfs.h" -bool use_browser; - const char perf_usage_string[] = "perf [--version] [--help] COMMAND [ARGS]"; const char perf_more_info_string[] = "See 'perf help COMMAND' for more information on a specific command."; +int use_browser = -1; static int use_pager = -1; + struct pager_config { const char *cmd; int val; @@ -49,6 +49,24 @@ int check_pager_config(const char *cmd) return c.val; } +static int tui_command_config(const char *var, const char *value, void *data) +{ + struct pager_config *c = data; + if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) + c->val = perf_config_bool(var, value); + return 0; +} + +/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */ +static int check_tui_config(const char *cmd) +{ + struct pager_config c; + c.cmd = cmd; + c.val = -1; + perf_config(tui_command_config, &c); + return c.val; +} + static void commit_pager_choice(void) { switch (use_pager) { @@ -255,6 +273,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (p->option & RUN_SETUP) prefix = NULL; /* setup_perf_directory(); */ + if (use_browser == -1) + use_browser = check_tui_config(p->cmd); + if (use_pager == -1 && p->option & RUN_SETUP) use_pager = check_pager_config(p->cmd); if (use_pager == -1 && p->option & USE_PAGER) diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 5eca52595b62..65fe664fddf6 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -30,7 +30,7 @@ extern const char *pager_program; extern int pager_in_use(void); extern int pager_use_color; -extern bool use_browser; +extern int use_browser; #ifdef NO_NEWT_SUPPORT static inline void setup_browser(void) diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 9338d060ee49..9d203c972f3b 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -1066,10 +1066,13 @@ static struct newtPercentTreeColors { void setup_browser(void) { struct newtPercentTreeColors *c = &defaultPercentTreeColors; - if (!isatty(1)) + + if (!isatty(1) || !use_browser) { + setup_pager(); return; + } - use_browser = true; + use_browser = 1; newtInit(); newtCls(); ui_helpline__puts(" "); @@ -1082,7 +1085,7 @@ void setup_browser(void) void exit_browser(bool wait_for_ok) { - if (use_browser) { + if (use_browser > 0) { if (wait_for_ok) { char title[] = "Fatal Error", ok[] = "Ok"; newtWinMessage(title, ok, browser__last_msg); -- cgit v1.2.3 From 57adc51dce9102b6641269dd04f5b99aac83b820 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 20 May 2010 14:39:55 +0200 Subject: perf-record: Remove -M Since it is not allowed to create cross-cpu (or cross-task) buffers, this option is no longer valid. Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <20100521090710.582740993@chello.nl> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e67226981834..94e210f86077 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -61,8 +61,6 @@ static bool call_graph = false; static bool inherit_stat = false; static bool no_samples = false; static bool sample_address = false; -static bool multiplex = false; -static int multiplex_fd = -1; static long samples = 0; static u64 bytes_written = 0; @@ -366,27 +364,19 @@ try_again: */ if (group && group_fd == -1) group_fd = fd[nr_cpu][counter][thread_index]; - if (multiplex && multiplex_fd == -1) - multiplex_fd = fd[nr_cpu][counter][thread_index]; - if (multiplex && fd[nr_cpu][counter][thread_index] != multiplex_fd) { - - ret = ioctl(fd[nr_cpu][counter][thread_index], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); - assert(ret != -1); - } else { - event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; - event_array[nr_poll].events = POLLIN; - nr_poll++; - - mmap_array[nr_cpu][counter][thread_index].counter = counter; - mmap_array[nr_cpu][counter][thread_index].prev = 0; - mmap_array[nr_cpu][counter][thread_index].mask = mmap_pages*page_size - 1; - mmap_array[nr_cpu][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); - if (mmap_array[nr_cpu][counter][thread_index].base == MAP_FAILED) { - error("failed to mmap with %d (%s)\n", errno, strerror(errno)); - exit(-1); - } + event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; + event_array[nr_poll].events = POLLIN; + nr_poll++; + + mmap_array[nr_cpu][counter][thread_index].counter = counter; + mmap_array[nr_cpu][counter][thread_index].prev = 0; + mmap_array[nr_cpu][counter][thread_index].mask = mmap_pages*page_size - 1; + mmap_array[nr_cpu][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); + if (mmap_array[nr_cpu][counter][thread_index].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); } if (filter != NULL) { @@ -820,8 +810,6 @@ static const struct option options[] = { "Sample addresses"), OPT_BOOLEAN('n', "no-samples", &no_samples, "don't sample"), - OPT_BOOLEAN('M', "multiplex", &multiplex, - "multiplex counter output in a single channel"), OPT_END() }; -- cgit v1.2.3 From 0e2e63dd608bf5844ffae7bf7d860de18a62724c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 20 May 2010 14:45:26 +0200 Subject: perf-record: Share per-cpu buffers It seems a waste of space to create a buffer per event, share it per-cpu. Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <20100521090710.634824884@chello.nl> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 52 ++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 94e210f86077..9bc89050e6f8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -82,7 +82,7 @@ struct mmap_data { unsigned int prev; }; -static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; +static struct mmap_data mmap_array[MAX_NR_CPUS]; static unsigned long mmap_read_head(struct mmap_data *md) { @@ -365,18 +365,29 @@ try_again: if (group && group_fd == -1) group_fd = fd[nr_cpu][counter][thread_index]; - event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; - event_array[nr_poll].events = POLLIN; - nr_poll++; - - mmap_array[nr_cpu][counter][thread_index].counter = counter; - mmap_array[nr_cpu][counter][thread_index].prev = 0; - mmap_array[nr_cpu][counter][thread_index].mask = mmap_pages*page_size - 1; - mmap_array[nr_cpu][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); - if (mmap_array[nr_cpu][counter][thread_index].base == MAP_FAILED) { - error("failed to mmap with %d (%s)\n", errno, strerror(errno)); - exit(-1); + if (counter || thread_index) { + ret = ioctl(fd[nr_cpu][counter][thread_index], + PERF_EVENT_IOC_SET_OUTPUT, + fd[nr_cpu][0][0]); + if (ret) { + error("failed to set output: %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + } else { + mmap_array[nr_cpu].counter = counter; + mmap_array[nr_cpu].prev = 0; + mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; + mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); + if (mmap_array[nr_cpu].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); + } + + event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; + event_array[nr_poll].events = POLLIN; + nr_poll++; } if (filter != NULL) { @@ -477,16 +488,11 @@ static struct perf_event_header finished_round_event = { static void mmap_read_all(void) { - int i, counter, thread; + int i; for (i = 0; i < nr_cpu; i++) { - for (counter = 0; counter < nr_counters; counter++) { - for (thread = 0; thread < thread_num; thread++) { - if (mmap_array[i][counter][thread].base) - mmap_read(&mmap_array[i][counter][thread]); - } - - } + if (mmap_array[i].base) + mmap_read(&mmap_array[i]); } if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) @@ -861,9 +867,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) for (i = 0; i < MAX_NR_CPUS; i++) { for (j = 0; j < MAX_COUNTERS; j++) { fd[i][j] = malloc(sizeof(int)*thread_num); - mmap_array[i][j] = zalloc( - sizeof(struct mmap_data)*thread_num); - if (!fd[i][j] || !mmap_array[i][j]) + if (!fd[i][j]) return -ENOMEM; } } -- cgit v1.2.3 From 598357eba6a55d27ddc7ead80ebb83fe1aad9b83 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 21 May 2010 12:48:39 +0200 Subject: perf: Fix getline undeclared MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to have stdio.h included with _GNU_SOURCEfopr getline, which is broken with the inclusion of build-id.h. Keep util.h included first in hist.c Fixes: util/hist.c: Dans la fonction «hist_entry__parse_objdump_line» : util/hist.c:938: attention : déclaration implicite de la fonction « «getline» » util/hist.c:938: attention : nested extern declaration of «getline» make: *** [util/hist.o] Erreur 1 Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras LKML-Reference: <1274438919-5104-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 739c39fd0ade..009ad76b0879 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1,5 +1,5 @@ -#include "build-id.h" #include "util.h" +#include "build-id.h" #include "hist.h" #include "session.h" #include "sort.h" -- cgit v1.2.3 From 0e8dc2597487848bb076d6b3d8440c85dde521e7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 21 May 2010 14:19:24 -0300 Subject: perf report: Don't start the TUI if -D is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One day we'll have support for the "dump raw trace in ASCII" in the TUI frontend, but till then, use the tty code. Reported-by: Peter Zijlstra Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a7b8760e401c..2c39bd358975 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -484,7 +484,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, report_usage, 0); - if (strcmp(input_name, "-") != 0) + if (dump_trace) + setup_pager(); + else if (strcmp(input_name, "-") != 0) setup_browser(); /* * Only in the newt browser we are doing integrated annotation, -- cgit v1.2.3 From 6e78c9fd1bc2c7e04b3d7052e9eb27aa536e4e2c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 May 2010 11:20:24 -0300 Subject: perf tui: Remove annotate from popup menu after failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 0b45658f7497..c65838c99354 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -914,6 +914,9 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na switch (toupper(es.u.key)) { case 'A': + if (browser->selection->map == NULL && + browser->selection->map->dso->annotate_warned) + continue; goto do_annotate; case 'D': goto zoom_dso; @@ -957,6 +960,7 @@ do_help: } if (browser->selection->sym != NULL && + !browser->selection->map->dso->annotate_warned && asprintf(&options[nr_options], "Annotate %s", browser->selection->sym->name) > 0) annotate = nr_options++; @@ -991,6 +995,7 @@ do_help: struct hist_entry *he; do_annotate: if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { + browser->selection->map->dso->annotate_warned = 1; ui_helpline__puts("No vmlinux file found, can't " "annotate with just a " "kallsyms file"); -- cgit v1.2.3 From 46e3e055ce69a00d735e458445ab1d24718ff751 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 May 2010 11:25:40 -0300 Subject: perf annotate: Add TUI interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When annotating multiple entries, for instance, when running simply as: $ perf annotate the right and left keys, as well as TAB can be used to cycle thru the multiple symbols being annotated. If one doesn't like TUI annotate, disable it by editing ~/.perfconfig and adding: [tui] annotate = off Just like it is possible for report. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 61 +++++++++++++++++++++++++++++++------------ tools/perf/builtin-report.c | 4 +-- tools/perf/util/hist.c | 13 ++++----- tools/perf/util/hist.h | 10 +++++++ tools/perf/util/newt.c | 56 +++++++++++++++++++++++++-------------- tools/perf/util/util.h | 15 ++++++++++- 6 files changed, 112 insertions(+), 47 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 77bcc9b130f5..08278eda31a5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -277,7 +277,7 @@ static void hist_entry__print_hits(struct hist_entry *self) printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); } -static void annotate_sym(struct hist_entry *he) +static int hist_entry__tty_annotate(struct hist_entry *he) { struct map *map = he->ms.map; struct dso *dso = map->dso; @@ -288,7 +288,7 @@ static void annotate_sym(struct hist_entry *he) struct objdump_line *pos, *n; if (hist_entry__annotate(he, &head) < 0) - return; + return -1; if (full_paths) d_filename = filename; @@ -317,30 +317,59 @@ static void annotate_sym(struct hist_entry *he) if (print_line) free_source_line(he, len); + + return 0; } static void hists__find_annotations(struct hists *self) { - struct rb_node *nd; + struct rb_node *first = rb_first(&self->entries), *nd = first; + int key = KEY_RIGHT; - for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { + while (nd) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct sym_priv *priv; - if (he->ms.sym == NULL) - continue; + if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) + goto find_next; priv = symbol__priv(he->ms.sym); - if (priv->hist == NULL) + if (priv->hist == NULL) { +find_next: + if (key == KEY_LEFT) + nd = rb_prev(nd); + else + nd = rb_next(nd); continue; + } - annotate_sym(he); - /* - * Since we have a hist_entry per IP for the same symbol, free - * he->ms.sym->hist to signal we already processed this symbol. - */ - free(priv->hist); - priv->hist = NULL; + if (use_browser) { + key = hist_entry__tui_annotate(he); + if (is_exit_key(key)) + break; + switch (key) { + case KEY_RIGHT: + case '\t': + nd = rb_next(nd); + break; + case KEY_LEFT: + if (nd == first) + continue; + nd = rb_prev(nd); + default: + break; + } + } else { + hist_entry__tty_annotate(he); + nd = rb_next(nd); + /* + * Since we have a hist_entry per IP for the same + * symbol, free he->ms.sym->hist to signal we already + * processed this symbol. + */ + free(priv->hist); + priv->hist = NULL; + } } } @@ -416,6 +445,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, annotate_usage, 0); + setup_browser(); + symbol_conf.priv_size = sizeof(struct sym_priv); symbol_conf.try_vmlinux_path = true; @@ -435,8 +466,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) sym_hist_filter = argv[0]; } - setup_pager(); - if (field_sep && *field_sep == '.') { pr_err("'.' is the only non valid --field-separator argument\n"); return -1; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2c39bd358975..a7b8760e401c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -484,9 +484,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, report_usage, 0); - if (dump_trace) - setup_pager(); - else if (strcmp(input_name, "-") != 0) + if (strcmp(input_name, "-") != 0) setup_browser(); /* * Only in the newt browser we are doing integrated annotation, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 009ad76b0879..682a6d88862c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -992,14 +992,14 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) char *filename = dso__build_id_filename(dso, NULL, 0); char command[PATH_MAX * 2]; FILE *file; - int err = -1; + int err = 0; u64 len; if (filename == NULL) { if (dso->has_build_id) { pr_err("Can't annotate %s: not enough memory\n", sym->name); - return -1; + return -ENOMEM; } /* * If we don't have build-ids, well, lets hope that this @@ -1009,14 +1009,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) } if (dso->origin == DSO__ORIG_KERNEL) { - if (dso->annotate_warned) { - err = 0; + if (dso->annotate_warned) goto out_free_filename; - } + err = -ENOENT; dso->annotate_warned = 1; pr_err("Can't annotate %s: No vmlinux file was found in the " - "path:\n", sym->name); - vmlinux_path__fprintf(stderr); + "path\n", sym->name); goto out_free_filename; } @@ -1046,7 +1044,6 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) break; pclose(file); - err = 0; out_free_filename: if (dso->has_build_id) free(filename); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 6f17dcd8412c..2d5203fedb20 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -102,8 +102,18 @@ static inline int hists__browse(struct hists *self __used, { return 0; } +static inline int hist_entry__tui_annotate(struct hist_entry *self __used) +{ + return 0; +} +#define KEY_LEFT -1 +#define KEY_RIGHT -2 #else +#include int hists__browse(struct hists *self, const char *helpline, const char *input_name); +int hist_entry__tui_annotate(struct hist_entry *self); +#define KEY_LEFT NEWT_KEY_LEFT +#define KEY_RIGHT NEWT_KEY_RIGHT #endif #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index c65838c99354..ffd04720b754 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -235,6 +235,15 @@ static bool dialog_yesno(const char *msg) return newtWinChoice(NULL, yes, no, (char *)msg) == 1; } +static void ui__error_window(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap); + va_end(ap); +} + #define HE_COLORSET_TOP 50 #define HE_COLORSET_MEDIUM 51 #define HE_COLORSET_NORMAL 52 @@ -386,6 +395,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, newtFormAddHotKey(self->form, ' '); newtFormAddHotKey(self->form, NEWT_KEY_HOME); newtFormAddHotKey(self->form, NEWT_KEY_END); + newtFormAddHotKey(self->form, NEWT_KEY_TAB); + newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); if (ui_browser__refresh_entries(self) < 0) return -1; @@ -398,6 +409,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, if (es->reason != NEWT_EXIT_HOTKEY) break; + if (is_exit_key(es->u.key)) + return es->u.key; switch (es->u.key) { case NEWT_KEY_DOWN: if (self->index == self->nr_entries - 1) @@ -471,12 +484,10 @@ static int ui_browser__run(struct ui_browser *self, const char *title, } } break; - case NEWT_KEY_ESCAPE: + case NEWT_KEY_RIGHT: case NEWT_KEY_LEFT: - case CTRL('c'): - case 'Q': - case 'q': - return 0; + case NEWT_KEY_TAB: + return es->u.key; default: continue; } @@ -668,18 +679,24 @@ static size_t hist_entry__append_browser(struct hist_entry *self, return ret; } -static void hist_entry__annotate_browser(struct hist_entry *self) +int hist_entry__tui_annotate(struct hist_entry *self) { struct ui_browser browser; struct newtExitStruct es; struct objdump_line *pos, *n; LIST_HEAD(head); + int ret; if (self->ms.sym == NULL) - return; + return -1; - if (hist_entry__annotate(self, &head) < 0) - return; + if (self->ms.map->dso->annotate_warned) + return -1; + + if (hist_entry__annotate(self, &head) < 0) { + ui__error_window(browser__last_msg); + return -1; + } ui_helpline__push("Press <- or ESC to exit"); @@ -694,7 +711,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) } browser.width += 18; /* Percentage */ - ui_browser__run(&browser, self->ms.sym->name, &es); + ret = ui_browser__run(&browser, self->ms.sym->name, &es); newtFormDestroy(browser.form); newtPopWindow(); list_for_each_entry_safe(pos, n, &head, node) { @@ -702,6 +719,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) objdump_line__free(pos); } ui_helpline__pop(); + return ret; } static const void *newt__symbol_tree_get_current(newtComponent self) @@ -935,14 +953,14 @@ do_help: continue; default:; } - if (toupper(es.u.key) == 'Q' || - es.u.key == CTRL('c')) - break; - if (es.u.key == NEWT_KEY_ESCAPE) { - if (dialog_yesno("Do you really want to exit?")) + if (is_exit_key(es.u.key)) { + if (es.u.key == NEWT_KEY_ESCAPE) { + if (dialog_yesno("Do you really want to exit?")) + break; + else + continue; + } else break; - else - continue; } if (es.u.key == NEWT_KEY_LEFT) { @@ -1006,7 +1024,7 @@ do_annotate: if (he == NULL) continue; - hist_entry__annotate_browser(he); + hist_entry__tui_annotate(he); } else if (choice == zoom_dso) { zoom_dso: if (dso_filter) { @@ -1074,7 +1092,7 @@ void setup_browser(void) { struct newtPercentTreeColors *c = &defaultPercentTreeColors; - if (!isatty(1) || !use_browser) { + if (!isatty(1) || !use_browser || dump_trace) { setup_pager(); return; } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 45b9655f3a5c..4e8b6b0c551c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -81,7 +81,7 @@ #include #include "../../../include/linux/magic.h" #include "types.h" - +#include #ifndef NO_ICONV #include @@ -263,6 +263,19 @@ bool strglobmatch(const char *str, const char *pat); bool strlazymatch(const char *str, const char *pat); unsigned long convert_unit(unsigned long value, char *unit); +#ifndef ESC +#define ESC 27 +#endif + +static inline bool is_exit_key(int key) +{ + char up; + if (key == CTRL('c') || key == ESC) + return true; + up = toupper(key); + return up == 'Q'; +} + #define _STR(x) #x #define STR(x) _STR(x) -- cgit v1.2.3 From 44bf460649a9b91f291176097e9d7e846e8c001e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 23 May 2010 19:12:25 -0300 Subject: perf annotate: Fix up usage of the build id cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was assuming that the cache was always available and also wasn't checking if the file found in the build id cache was just a kallsyms file, that is not supported by objdump for disassembly. Reported-by: Ingo Molnar Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 682a6d88862c..cbf7eae2ce09 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -990,6 +990,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) struct map *map = self->ms.map; struct dso *dso = map->dso; char *filename = dso__build_id_filename(dso, NULL, 0); + bool free_filename = true; char command[PATH_MAX * 2]; FILE *file; int err = 0; @@ -1001,11 +1002,19 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) sym->name); return -ENOMEM; } + goto fallback; + } else if (readlink(filename, command, sizeof(command)) < 0 || + strstr(command, "[kernel.kallsyms]") || + access(filename, R_OK)) { + free(filename); +fallback: /* - * If we don't have build-ids, well, lets hope that this + * If we don't have build-ids or the build-id file isn't in the + * cache, or is just a kallsyms file, well, lets hope that this * DSO is the same as when 'perf record' ran. */ filename = dso->long_name; + free_filename = false; } if (dso->origin == DSO__ORIG_KERNEL) { @@ -1045,7 +1054,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) pclose(file); out_free_filename: - if (dso->has_build_id) + if (free_filename) free(filename); return err; } -- cgit v1.2.3 From d67f088e084755bdceb4f15bc6e05e309db1eea7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 23 May 2010 22:36:51 -0300 Subject: perf report: Support multiple events on the TUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hists__tty_browse_tree function was created with the loop to print all events, and its equivalent, hists__tui_browse_tree, was created in a similar fashion, where it is possible to switch among the multiple events, if present, using TAB to go the next event, and shift+TAB (UNTAB) to go to the previous. The report TUI now shows as the window title the name of the event and a leak was fixed wrt pstacks. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 60 +++++++++++++++++++++--------------- tools/perf/util/hist.h | 14 +++++++-- tools/perf/util/newt.c | 74 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 108 insertions(+), 40 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a7b8760e401c..359205782964 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -288,6 +288,38 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, return ret + fprintf(fp, "\n#\n"); } +static int hists__tty_browse_tree(struct rb_root *tree, const char *help) +{ + struct rb_node *next = rb_first(tree); + + while (next) { + struct hists *hists = rb_entry(next, struct hists, rb_node); + const char *evname = NULL; + + if (rb_first(&hists->entries) != rb_last(&hists->entries)) + evname = __event_name(hists->type, hists->config); + + hists__fprintf_nr_sample_events(hists, evname, stdout); + hists__fprintf(hists, NULL, false, stdout); + fprintf(stdout, "\n\n"); + next = rb_next(&hists->rb_node); + } + + if (sort_order == default_sort_order && + parent_pattern == default_parent_pattern) { + fprintf(stdout, "#\n# (%s)\n#\n", help); + + if (show_threads) { + bool style = !strcmp(pretty_printing_style, "raw"); + perf_read_values_display(stdout, &show_threads_values, + style); + perf_read_values_destroy(&show_threads_values); + } + } + + return 0; +} + static int __cmd_report(void) { int ret = -EINVAL; @@ -330,34 +362,14 @@ static int __cmd_report(void) hists = rb_entry(next, struct hists, rb_node); hists__collapse_resort(hists); hists__output_resort(hists); - if (use_browser > 0) - hists__browse(hists, help, input_name); - else { - const char *evname = NULL; - if (rb_first(&session->hists.entries) != - rb_last(&session->hists.entries)) - evname = __event_name(hists->type, hists->config); - - hists__fprintf_nr_sample_events(hists, evname, stdout); - - hists__fprintf(hists, NULL, false, stdout); - fprintf(stdout, "\n\n"); - } - next = rb_next(&hists->rb_node); } - if (use_browser <= 0 && sort_order == default_sort_order && - parent_pattern == default_parent_pattern) { - fprintf(stdout, "#\n# (%s)\n#\n", help); + if (use_browser > 0) + hists__tui_browse_tree(&session->hists_tree, help); + else + hists__tty_browse_tree(&session->hists_tree, help); - if (show_threads) { - bool style = !strcmp(pretty_printing_style, "raw"); - perf_read_values_display(stdout, &show_threads_values, - style); - perf_read_values_destroy(&show_threads_values); - } - } out_delete: perf_session__delete(session); return ret; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2d5203fedb20..83fa33a7b38b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -98,10 +98,17 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread); #ifdef NO_NEWT_SUPPORT static inline int hists__browse(struct hists *self __used, const char *helpline __used, - const char *input_name __used) + const char *ev_name __used) { return 0; } + +static inline int hists__tui_browse_tree(struct rb_root *self __used, + const char *help __used) +{ + return 0; +} + static inline int hist_entry__tui_annotate(struct hist_entry *self __used) { return 0; @@ -111,9 +118,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used) #else #include int hists__browse(struct hists *self, const char *helpline, - const char *input_name); + const char *ev_name); int hist_entry__tui_annotate(struct hist_entry *self); + #define KEY_LEFT NEWT_KEY_LEFT #define KEY_RIGHT NEWT_KEY_RIGHT + +int hists__tui_browse_tree(struct rb_root *self, const char *help); #endif #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index ffd04720b754..d54c540f49db 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -842,6 +842,8 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists newtFormAddHotKey(self->form, 'h'); newtFormAddHotKey(self->form, NEWT_KEY_F1); newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); + newtFormAddHotKey(self->form, NEWT_KEY_TAB); + newtFormAddHotKey(self->form, NEWT_KEY_UNTAB); newtFormAddComponents(self->form, self->tree, NULL); self->selection = newt__symbol_tree_get_current(self->tree); @@ -873,7 +875,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) return he ? he->thread : NULL; } -static int hist_browser__title(char *bf, size_t size, const char *input_name, +static int hist_browser__title(char *bf, size_t size, const char *ev_name, const struct dso *dso, const struct thread *thread) { int printed = 0; @@ -887,18 +889,18 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name, printed += snprintf(bf + printed, size - printed, "%sDSO: %s", thread ? " " : "", dso->short_name); - return printed ?: snprintf(bf, size, "Report: %s", input_name); + return printed ?: snprintf(bf, size, "Event: %s", ev_name); } -int hists__browse(struct hists *self, const char *helpline, const char *input_name) +int hists__browse(struct hists *self, const char *helpline, const char *ev_name) { struct hist_browser *browser = hist_browser__new(); - struct pstack *fstack = pstack__new(2); + struct pstack *fstack; const struct thread *thread_filter = NULL; const struct dso *dso_filter = NULL; struct newtExitStruct es; char msg[160]; - int err = -1; + int key = -1; if (browser == NULL) return -1; @@ -909,7 +911,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na ui_helpline__push(helpline); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out_free_stack; @@ -927,10 +929,23 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na dso = browser->selection->map ? browser->selection->map->dso : NULL; if (es.reason == NEWT_EXIT_HOTKEY) { - if (es.u.key == NEWT_KEY_F1) + key = es.u.key; + + switch (key) { + case NEWT_KEY_F1: goto do_help; + case NEWT_KEY_TAB: + case NEWT_KEY_UNTAB: + /* + * Exit the browser, let hists__browser_tree + * go to the next or previous + */ + goto out_free_stack; + default:; + } - switch (toupper(es.u.key)) { + key = toupper(key); + switch (key) { case 'A': if (browser->selection->map == NULL && browser->selection->map->dso->annotate_warned) @@ -953,8 +968,8 @@ do_help: continue; default:; } - if (is_exit_key(es.u.key)) { - if (es.u.key == NEWT_KEY_ESCAPE) { + if (is_exit_key(key)) { + if (key == NEWT_KEY_ESCAPE) { if (dialog_yesno("Do you really want to exit?")) break; else @@ -1041,7 +1056,7 @@ zoom_out_dso: pstack__push(fstack, &dso_filter); } hists__filter_by_dso(self, dso_filter); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out; @@ -1060,18 +1075,49 @@ zoom_out_thread: pstack__push(fstack, &thread_filter); } hists__filter_by_thread(self, thread_filter); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out; } } - err = 0; out_free_stack: pstack__delete(fstack); out: hist_browser__delete(browser); - return err; + return key; +} + +int hists__tui_browse_tree(struct rb_root *self, const char *help) +{ + struct rb_node *first = rb_first(self), *nd = first, *next; + int key = 0; + + while (nd) { + struct hists *hists = rb_entry(nd, struct hists, rb_node); + const char *ev_name = __event_name(hists->type, hists->config); + + key = hists__browse(hists, help, ev_name); + + if (is_exit_key(key)) + break; + + switch (key) { + case NEWT_KEY_TAB: + next = rb_next(nd); + if (next) + nd = next; + break; + case NEWT_KEY_UNTAB: + if (nd == first) + continue; + nd = rb_prev(nd); + default: + break; + } + } + + return key; } static struct newtPercentTreeColors { -- cgit v1.2.3