diff options
author | Ingo Molnar | 2017-04-12 07:29:13 +0200 |
---|---|---|
committer | Ingo Molnar | 2017-04-12 09:22:19 +0200 |
commit | ef0eb2e6447f562bae2bcf503afcd85d68e843cc (patch) | |
tree | c6c89a26511e564efe85c1e69132aedd439c932d | |
parent | 1c4f8ad81c7f13314e4357550be9d5be3754fed9 (diff) | |
parent | 986a5bc028a84d487c354a529730b48682d1fb41 (diff) |
Merge tag 'perf-core-for-mingo-4.12-20170411' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
perf/core improvements and fixes:
User visible changes:
- Support s390 jump instructions in perf annotate (Christian Borntraeger)
- When failing to setup multiple events (e.g. '-e irq_vectors:*'), state
which one caused the failure (Yao Jin)
- Various fixes for pipe mode, where the output of 'perf record' is
written to stdout instead of to a perf.data file, fixing workloads
such as: (David Carrillo-Cisneros)
$ perf record -o - noploop | perf inject -b > perf.data
$ perf record -o - noploop | perf annotate
Infrastructure changes:
- Simplify ltrim() implementation (Arnaldo Carvalho de Melo)
- Use ltrim() and rtrim() in places where ad-hoc equivalents were being
used (Taeung Song)
Conflicts:
tools/perf/util/annotate.c
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf.data-file-format.txt | 19 | ||||
-rw-r--r-- | tools/perf/arch/s390/annotate/instructions.c | 30 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-inject.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 10 | ||||
-rw-r--r-- | tools/perf/ui/browser.c | 2 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 48 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 4 | ||||
-rw-r--r-- | tools/perf/util/event.c | 11 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 8 | ||||
-rw-r--r-- | tools/perf/util/header.c | 3 | ||||
-rw-r--r-- | tools/perf/util/ordered-events.c | 3 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 3 | ||||
-rw-r--r-- | tools/perf/util/session.c | 17 | ||||
-rw-r--r-- | tools/perf/util/string.c | 6 |
16 files changed, 99 insertions, 73 deletions
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index b664b18d3991..fa2a9132f0a9 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -11,8 +11,8 @@ All fields are in native-endian of the machine that generated the perf.data. When perf is writing to a pipe it uses a special version of the file format that does not rely on seeking to adjust data offsets. This -format is not described here. The pipe version can be converted to -normal perf.data with perf inject. +format is described in "Pipe-mode data" section. The pipe data version can be +augmented with additional events using perf inject. The file starts with a perf_header: @@ -411,6 +411,21 @@ An array bound by the perf_file_section size. ids points to a array of uint64_t defining the ids for event attr attr. +Pipe-mode data + +Pipe-mode avoid seeks in the file by removing the perf_file_section and flags +from the struct perf_header. The trimmed header is: + +struct perf_pipe_file_header { + u64 magic; + u64 size; +}; + +The information about attrs, data, and event_types is instead in the +synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA and +PERF_RECORD_HEADER_EVENT_TYPE that are generated by perf record in pipe-mode. + + References: include/uapi/linux/perf_event.h diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c new file mode 100644 index 000000000000..745b4b1b8b21 --- /dev/null +++ b/tools/perf/arch/s390/annotate/instructions.c @@ -0,0 +1,30 @@ +static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name) +{ + struct ins_ops *ops = NULL; + + /* catch all kind of jumps */ + if (strchr(name, 'j') || + !strncmp(name, "bct", 3) || + !strncmp(name, "br", 2)) + ops = &jump_ops; + /* override call/returns */ + if (!strcmp(name, "bras") || + !strcmp(name, "brasl") || + !strcmp(name, "basr")) + ops = &call_ops; + if (!strcmp(name, "br")) + ops = &ret_ops; + + arch__associate_ins_ops(arch, name, ops); + return ops; +} + +static int s390__annotate_init(struct arch *arch) +{ + if (!arch->initialized) { + arch->initialized = true; + arch->associate_instruction_ops = s390__associate_ins_ops; + } + + return 0; +} diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 56a7c8d210b9..b2b2722f6bb7 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -394,6 +394,8 @@ int cmd_annotate(int argc, const char **argv) .exit = perf_event__process_exit, .fork = perf_event__process_fork, .namespaces = perf_event__process_namespaces, + .attr = perf_event__process_attr, + .build_id = perf_event__process_build_id, .ordered_events = true, .ordering_requires_timestamps = true, }, diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 42dff0b1375a..65e1c026a2f0 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -694,6 +694,8 @@ static int __cmd_inject(struct perf_inject *inject) lseek(fd, output_data_offset, SEEK_SET); ret = perf_session__process_events(session); + if (ret) + return ret; if (!file_out->is_pipe) { if (inject->build_ids) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 46acc8ece41f..2dab70fba2ba 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1708,7 +1708,7 @@ static int parse_scriptname(const struct option *opt __maybe_unused, static int parse_output_fields(const struct option *opt __maybe_unused, const char *arg, int unset __maybe_unused) { - char *tok; + char *tok, *strtok_saveptr = NULL; int i, imax = ARRAY_SIZE(all_output_options); int j; int rc = 0; @@ -1769,7 +1769,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, } } - for (tok = strtok(tok, ","); tok; tok = strtok(NULL, ",")) { + for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { for (i = 0; i < imax; ++i) { if (strcmp(tok, all_output_options[i].str) == 0) break; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2158ea14da57..868e086a6b59 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -875,10 +875,7 @@ static void print_metric_csv(void *ctx, return; } snprintf(buf, sizeof(buf), fmt, val); - vals = buf; - while (isspace(*vals)) - vals++; - ends = vals; + ends = vals = ltrim(buf); while (isdigit(*ends) || *ends == '.') ends++; *ends = 0; @@ -950,10 +947,7 @@ static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, return; unit = fixunit(tbuf, os->evsel, unit); snprintf(buf, sizeof buf, fmt, val); - vals = buf; - while (isspace(*vals)) - vals++; - ends = vals; + ends = vals = ltrim(buf); while (isdigit(*ends) || *ends == '.') ends++; *ends = 0; diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 3eb3edb307a4..9e47ccbe07f1 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -579,7 +579,7 @@ static int ui_browser__color_config(const char *var, const char *value, break; *bg = '\0'; - while (isspace(*++bg)); + bg = ltrim(++bg); ui_browser__colorsets[i].bg = bg; ui_browser__colorsets[i].fg = fg; return 0; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bfb2f1d393d5..30498a2d4a6f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -108,6 +108,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i #include "arch/arm64/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c" +#include "arch/s390/annotate/instructions.c" static struct arch architectures[] = { { @@ -132,6 +133,7 @@ static struct arch architectures[] = { }, { .name = "s390", + .init = s390__annotate_init, .objdump = { .comment_char = '#', }, @@ -385,9 +387,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m if (comment == NULL) return 0; - while (comment[0] != '\0' && isspace(comment[0])) - ++comment; - + comment = ltrim(comment); comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); @@ -432,9 +432,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops if (comment == NULL) return 0; - while (comment[0] != '\0' && isspace(comment[0])) - ++comment; - + comment = ltrim(comment); comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); return 0; @@ -783,10 +781,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, str static int disasm_line__parse(char *line, const char **namep, char **rawp) { - char *name = line, tmp; - - while (isspace(name[0])) - ++name; + char tmp, *name = ltrim(line); if (name[0] == '\0') return -1; @@ -804,12 +799,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp) goto out_free_name; (*rawp)[0] = tmp; - - if ((*rawp)[0] != '\0') { - (*rawp)++; - while (isspace((*rawp)[0])) - ++(*rawp); - } + *rawp = ltrim(*rawp); return 0; @@ -1154,7 +1144,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, { struct annotation *notes = symbol__annotation(sym); struct disasm_line *dl; - char *line = NULL, *parsed_line, *tmp, *tmp2, *c; + char *line = NULL, *parsed_line, *tmp, *tmp2; size_t line_len; s64 line_ip, offset = -1; regmatch_t match[2]; @@ -1165,32 +1155,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, if (!line) return -1; - while (line_len != 0 && isspace(line[line_len - 1])) - line[--line_len] = '\0'; - - c = strchr(line, '\n'); - if (c) - *c = 0; - line_ip = -1; - parsed_line = line; + parsed_line = rtrim(line); /* /filename:linenr ? Save line number and ignore. */ - if (regexec(&file_lineno, line, 2, match, 0) == 0) { - *line_nr = atoi(line + match[1].rm_so); + if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { + *line_nr = atoi(parsed_line + match[1].rm_so); return 0; } - /* - * Strip leading spaces: - */ - tmp = line; - while (*tmp) { - if (*tmp != ' ') - break; - tmp++; - } - + tmp = ltrim(parsed_line); if (*tmp) { /* * Parse hexa addresses followed by ':' diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 3cea1fb5404b..2e5eff5abef0 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -116,7 +116,7 @@ static int __parse_callchain_report_opt(const char *arg, bool allow_record_opt) { char *tok; - char *endptr; + char *endptr, *saveptr = NULL; bool minpcnt_set = false; bool record_opt_set = false; bool try_stack_size = false; @@ -127,7 +127,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) if (!arg) return 0; - while ((tok = strtok((char *)arg, ",")) != NULL) { + while ((tok = strtok_r((char *)arg, ",", &saveptr)) != NULL) { if (!strncmp(tok, "none", strlen(tok))) { callchain_param.mode = CHAIN_NONE; callchain_param.enabled = false; diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 76b9c6bc8369..8255a26ac255 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -106,7 +106,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, int fd; size_t size = 0; ssize_t n; - char *nl, *name, *tgids, *ppids; + char *name, *tgids, *ppids; *tgid = -1; *ppid = -1; @@ -134,14 +134,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, if (name) { name += 5; /* strlen("Name:") */ - - while (*name && isspace(*name)) - ++name; - - nl = strchr(name, '\n'); - if (nl) - *nl = '\0'; - + name = rtrim(ltrim(name)); size = strlen(name); if (size >= len) size = len - 1; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9dc7e2d6e48a..8f5d86bd3501 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2457,11 +2457,17 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, int err, char *msg, size_t size) { char sbuf[STRERR_BUFSIZE]; + int printed = 0; switch (err) { case EPERM: case EACCES: - return scnprintf(msg, size, + if (err == EPERM) + printed = scnprintf(msg, size, + "No permission to enable %s event.\n\n", + perf_evsel__name(evsel)); + + return scnprintf(msg + printed, size - printed, "You may not have permission to collect %sstats.\n\n" "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" "which controls use of the performance events system by\n" diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ef09f26e67da..2ccc7f06db79 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2270,6 +2270,9 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) perf_header__process_sections(header, fd, &hd, perf_file_section__fprintf_info); + if (session->file->is_pipe) + return 0; + fprintf(fp, "# missing features: "); for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) { if (bit) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index fe84df1875aa..e70e935b1841 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -79,7 +79,7 @@ static union perf_event *dup_event(struct ordered_events *oe, static void free_dup_event(struct ordered_events *oe, union perf_event *event) { - if (oe->copy_on_queue) { + if (event && oe->copy_on_queue) { oe->cur_alloc_size -= event->header.size; free(event); } @@ -150,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve list_move(&event->list, &oe->cache); oe->nr_events--; free_dup_event(oe, event->event); + event->event = NULL; } int ordered_events__queue(struct ordered_events *oe, union perf_event *event, diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 362051ea7f3d..11c752561c55 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1148,8 +1148,7 @@ static void wordwrap(char *s, int start, int max, int corr) break; s += wlen; column += n; - while (isspace(*s)) - s++; + s = ltrim(s); } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 24259bc2c598..7b740a73e595 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -140,8 +140,14 @@ struct perf_session *perf_session__new(struct perf_data_file *file, if (perf_session__open(session) < 0) goto out_close; - perf_session__set_id_hdr_size(session); - perf_session__set_comm_exec(session); + /* + * set session attributes that are present in perf.data + * but not in pipe-mode. + */ + if (!file->is_pipe) { + perf_session__set_id_hdr_size(session); + perf_session__set_comm_exec(session); + } } } else { session->machines.host.env = &perf_env; @@ -156,7 +162,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file, pr_warning("Cannot read kernel map\n"); } - if (tool && tool->ordering_requires_timestamps && + /* + * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is + * processed, so perf_evlist__sample_id_all is not meaningful here. + */ + if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps && tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_events = false; @@ -1656,6 +1666,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session) buf = malloc(cur_size); if (!buf) return -errno; + ordered_events__set_copy_on_queue(oe, true); more: event = buf; err = readn(fd, event, sizeof(struct perf_event_header)); diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index bddca519dd58..e8feb142c9c9 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -322,12 +322,8 @@ char *strxfrchar(char *s, char from, char to) */ char *ltrim(char *s) { - int len = strlen(s); - - while (len && isspace(*s)) { - len--; + while (isspace(*s)) s++; - } return s; } |