perf/core improvements and fixes:

User visible:
 
 - 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:
 
 - Simplify ltrim() implementation (Arnaldo Carvalho de Melo)
 
 - Use ltrim() and rtrim() in places where ad-hoc equivalents were being
   used (Taeung Song)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJY7XifAAoJENZQFvNTUqpAE/UP+gNIPRukyQe6aO/Vn7SXEfy5
 /9I/4GYsqOtsIW6ildfrHRadY9oasqrtLvVu5dlc1S0O2MDJDu1jOXfNnSevJxsY
 FwVzo2NuDh8rve0oWOQ10JyiXplhrtVAkAeNwudEoJLaxpZTWFLRzpmqYR1xf4PA
 TBHQdz7s7q81xJgALPCZ/4Pnw/Wj/cIWhPD1Xda+nSWBwGrw9+V0glZ08aWCxmps
 /fFSWr0/gEy6gfWaYHRsRlzydLgmm/YiEDusJqujSpyGXdXy1JEbHX07VPUx/zxu
 lwn/lJw1zbRl7r97y1VoYJpu3/x1rtOZK/Fu7if4evbaaevwdwgdFCHYLFl2QJcq
 V4f23zMNqdXAI8SmrQobHN/sHV0MXh/TWGNEt02wdzH4hpuqmV5eC2tQEBieZefb
 GqgUk+x55g4RAesXvsWa7QCUTlxauGEmSOzaroav+LaN6h8ByYJLisW9qESJgbiM
 VNftDHLVgy7ppIHL6lJsqEoBIOLhOIrZNXW6ADM2DJOQLoM5uGezGbdFEHFbhh4Q
 WbV+b0fAP1noxHsg6RJiq/VutRJfNyqtz4gMZhVKtjCDPIeUoKUKAnhbtI7iH6Cs
 albCEp8Ku/l3a+m4qmxXDkDybCAGNbd7K2UeLc1upizaQREqmNYAD1TPEjdX2A1H
 OhSnpE1v4AB2zJKYXQAq
 =sSXY
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Ingo Molnar 2017-04-12 07:29:13 +02:00
commit ef0eb2e644
16 changed files with 99 additions and 73 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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,
},

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 ':'

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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)

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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;
}