forked from Minki/linux
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:
commit
ef0eb2e644
@ -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
|
||||
|
30
tools/perf/arch/s390/annotate/instructions.c
Normal file
30
tools/perf/arch/s390/annotate/instructions.c
Normal 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;
|
||||
}
|
@ -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,
|
||||
},
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 ':'
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user