Commit ef0eb2e6 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-4.12-20170411' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 1c4f8ad8 986a5bc0
...@@ -11,8 +11,8 @@ All fields are in native-endian of the machine that generated the perf.data. ...@@ -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 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 that does not rely on seeking to adjust data offsets. This
format is not described here. The pipe version can be converted to format is described in "Pipe-mode data" section. The pipe data version can be
normal perf.data with perf inject. augmented with additional events using perf inject.
The file starts with a perf_header: The file starts with a perf_header:
...@@ -411,6 +411,21 @@ An array bound by the perf_file_section size. ...@@ -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. 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: References:
include/uapi/linux/perf_event.h include/uapi/linux/perf_event.h
......
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;
}
...@@ -394,6 +394,8 @@ int cmd_annotate(int argc, const char **argv) ...@@ -394,6 +394,8 @@ int cmd_annotate(int argc, const char **argv)
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.namespaces = perf_event__process_namespaces, .namespaces = perf_event__process_namespaces,
.attr = perf_event__process_attr,
.build_id = perf_event__process_build_id,
.ordered_events = true, .ordered_events = true,
.ordering_requires_timestamps = true, .ordering_requires_timestamps = true,
}, },
......
...@@ -694,6 +694,8 @@ static int __cmd_inject(struct perf_inject *inject) ...@@ -694,6 +694,8 @@ static int __cmd_inject(struct perf_inject *inject)
lseek(fd, output_data_offset, SEEK_SET); lseek(fd, output_data_offset, SEEK_SET);
ret = perf_session__process_events(session); ret = perf_session__process_events(session);
if (ret)
return ret;
if (!file_out->is_pipe) { if (!file_out->is_pipe) {
if (inject->build_ids) if (inject->build_ids)
......
...@@ -1708,7 +1708,7 @@ static int parse_scriptname(const struct option *opt __maybe_unused, ...@@ -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, static int parse_output_fields(const struct option *opt __maybe_unused,
const char *arg, int unset __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 i, imax = ARRAY_SIZE(all_output_options);
int j; int j;
int rc = 0; int rc = 0;
...@@ -1769,7 +1769,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, ...@@ -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) { for (i = 0; i < imax; ++i) {
if (strcmp(tok, all_output_options[i].str) == 0) if (strcmp(tok, all_output_options[i].str) == 0)
break; break;
......
...@@ -875,10 +875,7 @@ static void print_metric_csv(void *ctx, ...@@ -875,10 +875,7 @@ static void print_metric_csv(void *ctx,
return; return;
} }
snprintf(buf, sizeof(buf), fmt, val); snprintf(buf, sizeof(buf), fmt, val);
vals = buf; ends = vals = ltrim(buf);
while (isspace(*vals))
vals++;
ends = vals;
while (isdigit(*ends) || *ends == '.') while (isdigit(*ends) || *ends == '.')
ends++; ends++;
*ends = 0; *ends = 0;
...@@ -950,10 +947,7 @@ static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, ...@@ -950,10 +947,7 @@ static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
return; return;
unit = fixunit(tbuf, os->evsel, unit); unit = fixunit(tbuf, os->evsel, unit);
snprintf(buf, sizeof buf, fmt, val); snprintf(buf, sizeof buf, fmt, val);
vals = buf; ends = vals = ltrim(buf);
while (isspace(*vals))
vals++;
ends = vals;
while (isdigit(*ends) || *ends == '.') while (isdigit(*ends) || *ends == '.')
ends++; ends++;
*ends = 0; *ends = 0;
......
...@@ -579,7 +579,7 @@ static int ui_browser__color_config(const char *var, const char *value, ...@@ -579,7 +579,7 @@ static int ui_browser__color_config(const char *var, const char *value,
break; break;
*bg = '\0'; *bg = '\0';
while (isspace(*++bg)); bg = ltrim(++bg);
ui_browser__colorsets[i].bg = bg; ui_browser__colorsets[i].bg = bg;
ui_browser__colorsets[i].fg = fg; ui_browser__colorsets[i].fg = fg;
return 0; return 0;
......
...@@ -108,6 +108,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i ...@@ -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/arm64/annotate/instructions.c"
#include "arch/x86/annotate/instructions.c" #include "arch/x86/annotate/instructions.c"
#include "arch/powerpc/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c"
#include "arch/s390/annotate/instructions.c"
static struct arch architectures[] = { static struct arch architectures[] = {
{ {
...@@ -132,6 +133,7 @@ static struct arch architectures[] = { ...@@ -132,6 +133,7 @@ static struct arch architectures[] = {
}, },
{ {
.name = "s390", .name = "s390",
.init = s390__annotate_init,
.objdump = { .objdump = {
.comment_char = '#', .comment_char = '#',
}, },
...@@ -385,9 +387,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m ...@@ -385,9 +387,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m
if (comment == NULL) if (comment == NULL)
return 0; return 0;
while (comment[0] != '\0' && isspace(comment[0])) comment = ltrim(comment);
++comment;
comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.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 ...@@ -432,9 +432,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops
if (comment == NULL) if (comment == NULL)
return 0; return 0;
while (comment[0] != '\0' && isspace(comment[0])) comment = ltrim(comment);
++comment;
comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
return 0; return 0;
...@@ -783,10 +781,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, str ...@@ -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) static int disasm_line__parse(char *line, const char **namep, char **rawp)
{ {
char *name = line, tmp; char tmp, *name = ltrim(line);
while (isspace(name[0]))
++name;
if (name[0] == '\0') if (name[0] == '\0')
return -1; return -1;
...@@ -804,12 +799,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp) ...@@ -804,12 +799,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
goto out_free_name; goto out_free_name;
(*rawp)[0] = tmp; (*rawp)[0] = tmp;
*rawp = ltrim(*rawp);
if ((*rawp)[0] != '\0') {
(*rawp)++;
while (isspace((*rawp)[0]))
++(*rawp);
}
return 0; return 0;
...@@ -1154,7 +1144,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -1154,7 +1144,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
{ {
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl; struct disasm_line *dl;
char *line = NULL, *parsed_line, *tmp, *tmp2, *c; char *line = NULL, *parsed_line, *tmp, *tmp2;
size_t line_len; size_t line_len;
s64 line_ip, offset = -1; s64 line_ip, offset = -1;
regmatch_t match[2]; regmatch_t match[2];
...@@ -1165,32 +1155,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -1165,32 +1155,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
if (!line) if (!line)
return -1; 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; line_ip = -1;
parsed_line = line; parsed_line = rtrim(line);
/* /filename:linenr ? Save line number and ignore. */ /* /filename:linenr ? Save line number and ignore. */
if (regexec(&file_lineno, line, 2, match, 0) == 0) { if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
*line_nr = atoi(line + match[1].rm_so); *line_nr = atoi(parsed_line + match[1].rm_so);
return 0; return 0;
} }
/* tmp = ltrim(parsed_line);
* Strip leading spaces:
*/
tmp = line;
while (*tmp) {
if (*tmp != ' ')
break;
tmp++;
}
if (*tmp) { if (*tmp) {
/* /*
* Parse hexa addresses followed by ':' * Parse hexa addresses followed by ':'
......
...@@ -116,7 +116,7 @@ static int ...@@ -116,7 +116,7 @@ static int
__parse_callchain_report_opt(const char *arg, bool allow_record_opt) __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
{ {
char *tok; char *tok;
char *endptr; char *endptr, *saveptr = NULL;
bool minpcnt_set = false; bool minpcnt_set = false;
bool record_opt_set = false; bool record_opt_set = false;
bool try_stack_size = false; bool try_stack_size = false;
...@@ -127,7 +127,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) ...@@ -127,7 +127,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
if (!arg) if (!arg)
return 0; return 0;
while ((tok = strtok((char *)arg, ",")) != NULL) { while ((tok = strtok_r((char *)arg, ",", &saveptr)) != NULL) {
if (!strncmp(tok, "none", strlen(tok))) { if (!strncmp(tok, "none", strlen(tok))) {
callchain_param.mode = CHAIN_NONE; callchain_param.mode = CHAIN_NONE;
callchain_param.enabled = false; callchain_param.enabled = false;
......
...@@ -106,7 +106,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, ...@@ -106,7 +106,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
int fd; int fd;
size_t size = 0; size_t size = 0;
ssize_t n; ssize_t n;
char *nl, *name, *tgids, *ppids; char *name, *tgids, *ppids;
*tgid = -1; *tgid = -1;
*ppid = -1; *ppid = -1;
...@@ -134,14 +134,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, ...@@ -134,14 +134,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
if (name) { if (name) {
name += 5; /* strlen("Name:") */ name += 5; /* strlen("Name:") */
name = rtrim(ltrim(name));
while (*name && isspace(*name))
++name;
nl = strchr(name, '\n');
if (nl)
*nl = '\0';
size = strlen(name); size = strlen(name);
if (size >= len) if (size >= len)
size = len - 1; size = len - 1;
......
...@@ -2457,11 +2457,17 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, ...@@ -2457,11 +2457,17 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
int err, char *msg, size_t size) int err, char *msg, size_t size)
{ {
char sbuf[STRERR_BUFSIZE]; char sbuf[STRERR_BUFSIZE];
int printed = 0;
switch (err) { switch (err) {
case EPERM: case EPERM:
case EACCES: 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" "You may not have permission to collect %sstats.\n\n"
"Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
"which controls use of the performance events system by\n" "which controls use of the performance events system by\n"
......
...@@ -2270,6 +2270,9 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) ...@@ -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_header__process_sections(header, fd, &hd,
perf_file_section__fprintf_info); perf_file_section__fprintf_info);
if (session->file->is_pipe)
return 0;
fprintf(fp, "# missing features: "); fprintf(fp, "# missing features: ");
for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) { for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
if (bit) if (bit)
......
...@@ -79,7 +79,7 @@ static union perf_event *dup_event(struct ordered_events *oe, ...@@ -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) 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; oe->cur_alloc_size -= event->header.size;
free(event); free(event);
} }
...@@ -150,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve ...@@ -150,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
list_move(&event->list, &oe->cache); list_move(&event->list, &oe->cache);
oe->nr_events--; oe->nr_events--;
free_dup_event(oe, event->event); free_dup_event(oe, event->event);
event->event = NULL;
} }
int ordered_events__queue(struct ordered_events *oe, union perf_event *event, int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
......
...@@ -1148,8 +1148,7 @@ static void wordwrap(char *s, int start, int max, int corr) ...@@ -1148,8 +1148,7 @@ static void wordwrap(char *s, int start, int max, int corr)
break; break;
s += wlen; s += wlen;
column += n; column += n;
while (isspace(*s)) s = ltrim(s);
s++;
} }
} }
......
...@@ -140,8 +140,14 @@ struct perf_session *perf_session__new(struct perf_data_file *file, ...@@ -140,8 +140,14 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
if (perf_session__open(session) < 0) if (perf_session__open(session) < 0)
goto out_close; 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 { } else {
session->machines.host.env = &perf_env; session->machines.host.env = &perf_env;
...@@ -156,7 +162,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file, ...@@ -156,7 +162,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
pr_warning("Cannot read kernel map\n"); 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)) { tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
tool->ordered_events = false; tool->ordered_events = false;
...@@ -1656,6 +1666,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session) ...@@ -1656,6 +1666,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
buf = malloc(cur_size); buf = malloc(cur_size);
if (!buf) if (!buf)
return -errno; return -errno;
ordered_events__set_copy_on_queue(oe, true);
more: more:
event = buf; event = buf;
err = readn(fd, event, sizeof(struct perf_event_header)); err = readn(fd, event, sizeof(struct perf_event_header));
......
...@@ -322,12 +322,8 @@ char *strxfrchar(char *s, char from, char to) ...@@ -322,12 +322,8 @@ char *strxfrchar(char *s, char from, char to)
*/ */
char *ltrim(char *s) char *ltrim(char *s)
{ {
int len = strlen(s); while (isspace(*s))
while (len && isspace(*s)) {
len--;
s++; s++;
}
return s; return s;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment