Skip to content

Commit

Permalink
Merge tag 'perf-core-for-mingo-20160510' of git://git.kernel.org/pub/…
Browse files Browse the repository at this point in the history
…scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- Recording 'dwarf' callchains do not need DWARF unwinding support (He Kuang)

- Print recently added perf_event_attr.write_backward bit flag in -vv
  verbose mode (Arnaldo Carvalho de Melo)

- Fix incorrect python db-export error message in 'perf script' (Chris Phlipot)

- Fix handling of zero-length symbols (Chris Phlipot)

- perf stat: Scale values by unit before metrics (Andi Kleen)

Infrastructure changes:

- Rewrite strbuf not to die(), making tools using it to check its
  return value instead (Masami Hiramatsu)

- Support reading from backward ring buffer, add a 'perf test' entry
  for it (Wang Nan)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed May 11, 2016
2 parents d295015 + 452e840 commit 38f5d8b
Show file tree
Hide file tree
Showing 27 changed files with 510 additions and 245 deletions.
18 changes: 10 additions & 8 deletions tools/perf/builtin-help.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static int check_emacsclient_version(void)
struct child_process ec_process;
const char *argv_ec[] = { "emacsclient", "--version", NULL };
int version;
int ret = -1;

/* emacsclient prints its version number on stderr */
memset(&ec_process, 0, sizeof(ec_process));
Expand All @@ -71,7 +72,10 @@ static int check_emacsclient_version(void)
fprintf(stderr, "Failed to start emacsclient.\n");
return -1;
}
strbuf_read(&buffer, ec_process.err, 20);
if (strbuf_read(&buffer, ec_process.err, 20) < 0) {
fprintf(stderr, "Failed to read emacsclient version\n");
goto out;
}
close(ec_process.err);

/*
Expand All @@ -82,8 +86,7 @@ static int check_emacsclient_version(void)

if (prefixcmp(buffer.buf, "emacsclient")) {
fprintf(stderr, "Failed to parse emacsclient version.\n");
strbuf_release(&buffer);
return -1;
goto out;
}

version = atoi(buffer.buf + strlen("emacsclient"));
Expand All @@ -92,12 +95,11 @@ static int check_emacsclient_version(void)
fprintf(stderr,
"emacsclient version '%d' too old (< 22).\n",
version);
strbuf_release(&buffer);
return -1;
}

} else
ret = 0;
out:
strbuf_release(&buffer);
return 0;
return ret;
}

static void exec_woman_emacs(const char *path, const char *page)
Expand Down
8 changes: 5 additions & 3 deletions tools/perf/perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,11 @@ static int handle_alias(int *argcp, const char ***argv)
if (*argcp > 1) {
struct strbuf buf;

strbuf_init(&buf, PATH_MAX);
strbuf_addstr(&buf, alias_string);
sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
if (strbuf_init(&buf, PATH_MAX) < 0 ||
strbuf_addstr(&buf, alias_string) < 0 ||
sq_quote_argv(&buf, (*argv) + 1,
PATH_MAX) < 0)
die("Failed to allocate memory.");
free(alias_string);
alias_string = buf.buf;
}
Expand Down
1 change: 1 addition & 0 deletions tools/perf/tests/Build
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ perf-y += cpumap.o
perf-y += stat.o
perf-y += event_update.o
perf-y += event-times.o
perf-y += backward-ring-buffer.o

$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
$(call rule_mkdir)
Expand Down
151 changes: 151 additions & 0 deletions tools/perf/tests/backward-ring-buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Test backward bit in event attribute, read ring buffer from end to
* beginning
*/

#include <perf.h>
#include <evlist.h>
#include <sys/prctl.h>
#include "tests.h"
#include "debug.h"

#define NR_ITERS 111

static void testcase(void)
{
int i;

for (i = 0; i < NR_ITERS; i++) {
char proc_name[10];

snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
prctl(PR_SET_NAME, proc_name);
}
}

static int count_samples(struct perf_evlist *evlist, int *sample_count,
int *comm_count)
{
int i;

for (i = 0; i < evlist->nr_mmaps; i++) {
union perf_event *event;

perf_evlist__mmap_read_catchup(evlist, i);
while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) {
const u32 type = event->header.type;

switch (type) {
case PERF_RECORD_SAMPLE:
(*sample_count)++;
break;
case PERF_RECORD_COMM:
(*comm_count)++;
break;
default:
pr_err("Unexpected record of type %d\n", type);
return TEST_FAIL;
}
}
}
return TEST_OK;
}

static int do_test(struct perf_evlist *evlist, int mmap_pages,
int *sample_count, int *comm_count)
{
int err;
char sbuf[STRERR_BUFSIZE];

err = perf_evlist__mmap(evlist, mmap_pages, true);
if (err < 0) {
pr_debug("perf_evlist__mmap: %s\n",
strerror_r(errno, sbuf, sizeof(sbuf)));
return TEST_FAIL;
}

perf_evlist__enable(evlist);
testcase();
perf_evlist__disable(evlist);

err = count_samples(evlist, sample_count, comm_count);
perf_evlist__munmap(evlist);
return err;
}


int test__backward_ring_buffer(int subtest __maybe_unused)
{
int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0;
char pid[16], sbuf[STRERR_BUFSIZE];
struct perf_evlist *evlist;
struct perf_evsel *evsel __maybe_unused;
struct parse_events_error parse_error;
struct record_opts opts = {
.target = {
.uid = UINT_MAX,
.uses_mmap = true,
},
.freq = 0,
.mmap_pages = 256,
.default_interval = 1,
};

snprintf(pid, sizeof(pid), "%d", getpid());
pid[sizeof(pid) - 1] = '\0';
opts.target.tid = opts.target.pid = pid;

evlist = perf_evlist__new();
if (!evlist) {
pr_debug("No ehough memory to create evlist\n");
return TEST_FAIL;
}

err = perf_evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist;
}

bzero(&parse_error, sizeof(parse_error));
err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error);
if (err) {
pr_debug("Failed to parse tracepoint event, try use root\n");
ret = TEST_SKIP;
goto out_delete_evlist;
}

perf_evlist__config(evlist, &opts, NULL);

/* Set backward bit, ring buffer should be writing from end */
evlist__for_each(evlist, evsel)
evsel->attr.write_backward = 1;

err = perf_evlist__open(evlist);
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
strerror_r(errno, sbuf, sizeof(sbuf)));
goto out_delete_evlist;
}

ret = TEST_FAIL;
err = do_test(evlist, opts.mmap_pages, &sample_count,
&comm_count);
if (err != TEST_OK)
goto out_delete_evlist;

if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
sample_count, comm_count);
goto out_delete_evlist;
}

err = do_test(evlist, 1, &sample_count, &comm_count);
if (err != TEST_OK)
goto out_delete_evlist;

ret = TEST_OK;
out_delete_evlist:
perf_evlist__delete(evlist);
return ret;
}
4 changes: 4 additions & 0 deletions tools/perf/tests/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ static struct test generic_tests[] = {
.desc = "Test events times",
.func = test__event_times,
},
{
.desc = "Test backward reading from ring buffer",
.func = test__backward_ring_buffer,
},
{
.func = NULL,
},
Expand Down
1 change: 1 addition & 0 deletions tools/perf/tests/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ int test__synthesize_stat(int subtest);
int test__synthesize_stat_round(int subtest);
int test__event_update(int subtest);
int test__event_times(int subtest);
int test__backward_ring_buffer(int subtest);

#if defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
Expand Down
1 change: 0 additions & 1 deletion tools/perf/util/Build
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ libperf-y += strlist.o
libperf-y += strfilter.o
libperf-y += top.o
libperf-y += usage.o
libperf-y += wrapper.o
libperf-y += dso.o
libperf-y += symbol.o
libperf-y += symbol_fprintf.o
Expand Down
19 changes: 0 additions & 19 deletions tools/perf/util/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,6 @@ int split_cmdline(char *cmdline, const char ***argv);

#define alloc_nr(x) (((x)+16)*3/2)

/*
* Realloc the buffer pointed at by variable 'x' so that it can hold
* at least 'nr' entries; the number of entries currently allocated
* is 'alloc', using the standard growing factor alloc_nr() macro.
*
* DO NOT USE any expression with side-effect for 'x' or 'alloc'.
*/
#define ALLOC_GROW(x, nr, alloc) \
do { \
if ((nr) > alloc) { \
if (alloc_nr(alloc) < (nr)) \
alloc = (nr); \
else \
alloc = alloc_nr(alloc); \
x = xrealloc((x), alloc * sizeof(*(x))); \
} \
} while(0)


static inline int is_absolute_path(const char *path)
{
return path[0] == '/';
Expand Down
52 changes: 24 additions & 28 deletions tools/perf/util/dwarf-aux.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,7 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
tmp = "*";
else if (tag == DW_TAG_subroutine_type) {
/* Function pointer */
strbuf_add(buf, "(function_type)", 15);
return 0;
return strbuf_add(buf, "(function_type)", 15);
} else {
if (!dwarf_diename(&type))
return -ENOENT;
Expand All @@ -927,14 +926,10 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
else if (tag == DW_TAG_enumeration_type)
tmp = "enum ";
/* Write a base name */
strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type));
return 0;
return strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type));
}
ret = die_get_typename(&type, buf);
if (ret == 0)
strbuf_addstr(buf, tmp);

return ret;
return ret ? ret : strbuf_addstr(buf, tmp);
}

/**
Expand All @@ -951,12 +946,10 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf)
ret = die_get_typename(vr_die, buf);
if (ret < 0) {
pr_debug("Failed to get type, make it unknown.\n");
strbuf_add(buf, " (unknown_type)", 14);
ret = strbuf_add(buf, " (unknown_type)", 14);
}

strbuf_addf(buf, "\t%s", dwarf_diename(vr_die));

return 0;
return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die));
}

#ifdef HAVE_DWARF_GETLOCATIONS
Expand Down Expand Up @@ -999,22 +992,24 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die,
}

while ((offset = dwarf_ranges(&scopes[1], offset, &base,
&start, &end)) > 0) {
&start, &end)) > 0) {
start -= entry;
end -= entry;

if (first) {
strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
name, start, end);
ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
name, start, end);
first = false;
} else {
strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
start, end);
ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
start, end);
}
if (ret < 0)
goto out;
}

if (!first)
strbuf_add(buf, "]>", 2);
ret = strbuf_add(buf, "]>", 2);

out:
free(scopes);
Expand Down Expand Up @@ -1054,31 +1049,32 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
return -EINVAL;

while ((offset = dwarf_getlocations(
&attr, offset, &base,
&start, &end, &op, &nops)) > 0) {
while ((offset = dwarf_getlocations(&attr, offset, &base,
&start, &end, &op, &nops)) > 0) {
if (start == 0) {
/* Single Location Descriptions */
ret = die_get_var_innermost_scope(sp_die, vr_die, buf);
return ret;
goto out;
}

/* Location Lists */
start -= entry;
end -= entry;
if (first) {
strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
name, start, end);
ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64,
name, start, end);
first = false;
} else {
strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
start, end);
ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64,
start, end);
}
if (ret < 0)
goto out;
}

if (!first)
strbuf_add(buf, "]>", 2);

ret = strbuf_add(buf, "]>", 2);
out:
return ret;
}
#else
Expand Down
Loading

0 comments on commit 38f5d8b

Please sign in to comment.