perf/core improvements and fixes
. Prep work for the DWARF CFI post unwinder, so that it doesn't uses perf_session in lots of places, just evlist/evsel is enough. . Make clean brace expansion fix for some shells, from Palmer Cox . Warn user just once per guest kernel when not finding kernel info, from David Ahern . perf test fix from Jiri Olsa . Fix error handling on event creation in perf top, from David Ahern . Fix check on perf_target__strnerror, from Namhyung Kim . Save the whole cmdline, from David Ahern Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJQG9hnAAoJENZQFvNTUqpAw4kP/iqal/TGlSHZ8p9Uki+ZDLle 2Y7ekbGATn58ST0uNCzvrCcufE4ByBziQ23bMKZesEDFgOMvrS/BbY/eo7Psf1WR f7BoEQBoZloTBIOiw9wn5NGbDrncgRLn9Rg8mmLJaEEiIDuciUC+FQ6tdZtWTp5F fCAqMvGUZ+WPokmnsn23/hA3JyngU2Xz+QA0qrQ19wArxTQrInAUCYAHX6B7GdKi zpkpPJfxYPOkveQG5et+hhldvCtec1sVPelrGx0m3+Oq6Cj5GTW354uUu23P74oR Mcx6RAHBV/znJ38NYqFAb52SNNbc2VpWNKEPL8pu+j7iEDrM2z7qhvTwNvR8u1gb h6tYYs4RIMfNeYujabRusCGY3n5rSI1T5lqk6iBhbZ8wq7TCJe3hY2nB4C+Si0rY j0hogKo3LFhSXPpdwoODSR8MwJQ75vqA9ReTfLE9uJ+h4KtTvJ1T10ifviAmZYbl ykL/O56QvMvc5wvN7UtbvZYHo7ArKmG/V/Bv5eJ9vjeLic0VjKnxLQiWU8KDYidw ZPyQD5yvKQEu4t4vEplto9zmXSb9bTGa41HPfPkz3gFO0efimRvPMIViBJCHm3dG sCF9nD6FFV/W4k3WLA5iE2VxrvclPK6pmTI4rFO9LjsSQQMPiNZM4lC+axx+UXnb r0vms9HVaemjNX5/UHju =y8ib -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent Pull perf/core fixes and some late updates from Arnaldo Carvalho de Melo: * Make clean brace expansion fix for some shells, from Palmer Cox * Warn user just once per guest kernel when not finding kernel info, from David Ahern * perf test fix from Jiri Olsa * Fix error handling on event creation in perf top, from David Ahern * Fix check on perf_target__strnerror, from Namhyung Kim * Save the whole cmdline, from David Ahern * Prep work for the DWARF CFI post unwinder, so that it doesn't uses perf_session in lots of places, just evlist/evsel is enough. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
8a06bf1400
24 changed files with 499 additions and 188 deletions
|
@ -319,6 +319,8 @@ LIB_H += $(ARCH_INCLUDE)
|
|||
LIB_H += util/cgroup.h
|
||||
LIB_H += $(TRACE_EVENT_DIR)event-parse.h
|
||||
LIB_H += util/target.h
|
||||
LIB_H += util/rblist.h
|
||||
LIB_H += util/intlist.h
|
||||
|
||||
LIB_OBJS += $(OUTPUT)util/abspath.o
|
||||
LIB_OBJS += $(OUTPUT)util/alias.o
|
||||
|
@ -383,6 +385,8 @@ LIB_OBJS += $(OUTPUT)util/xyarray.o
|
|||
LIB_OBJS += $(OUTPUT)util/cpumap.o
|
||||
LIB_OBJS += $(OUTPUT)util/cgroup.o
|
||||
LIB_OBJS += $(OUTPUT)util/target.o
|
||||
LIB_OBJS += $(OUTPUT)util/rblist.o
|
||||
LIB_OBJS += $(OUTPUT)util/intlist.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
|
||||
|
||||
|
@ -983,7 +987,8 @@ clean:
|
|||
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
|
||||
$(MAKE) -C Documentation/ clean
|
||||
$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
|
||||
$(RM) $(OUTPUT)util/*-{bison,flex}*
|
||||
$(RM) $(OUTPUT)util/*-bison*
|
||||
$(RM) $(OUTPUT)util/*-flex*
|
||||
$(python-clean)
|
||||
|
||||
.PHONY: all install clean strip $(LIBTRACEEVENT)
|
||||
|
|
|
@ -313,7 +313,7 @@ try_again:
|
|||
}
|
||||
}
|
||||
|
||||
perf_session__update_sample_type(session);
|
||||
perf_session__set_id_hdr_size(session);
|
||||
}
|
||||
|
||||
static int process_buildids(struct perf_record *rec)
|
||||
|
@ -844,8 +844,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
|
|||
struct perf_record *rec = &record;
|
||||
char errbuf[BUFSIZ];
|
||||
|
||||
perf_header__set_cmdline(argc, argv);
|
||||
|
||||
evsel_list = perf_evlist__new(NULL, NULL);
|
||||
if (evsel_list == NULL)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -249,8 +249,9 @@ static int process_read_event(struct perf_tool *tool,
|
|||
static int perf_report__setup_sample_type(struct perf_report *rep)
|
||||
{
|
||||
struct perf_session *self = rep->session;
|
||||
u64 sample_type = perf_evlist__sample_type(self->evlist);
|
||||
|
||||
if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
||||
if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
||||
if (sort__has_parent) {
|
||||
ui__error("Selected --sort parent, but no "
|
||||
"callchain data. Did you call "
|
||||
|
@ -274,7 +275,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
|
|||
|
||||
if (sort__branch_mode == 1) {
|
||||
if (!self->fd_pipe &&
|
||||
!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
|
||||
!(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
|
||||
ui__error("Selected -b but no branch data. "
|
||||
"Did you call perf record without -b?\n");
|
||||
return -1;
|
||||
|
|
|
@ -478,7 +478,6 @@ static int test__basic_mmap(void)
|
|||
unsigned int nr_events[nsyscalls],
|
||||
expected_nr_events[nsyscalls], i, j;
|
||||
struct perf_evsel *evsels[nsyscalls], *evsel;
|
||||
int sample_size = __perf_evsel__sample_size(attr.sample_type);
|
||||
|
||||
for (i = 0; i < nsyscalls; ++i) {
|
||||
char name[64];
|
||||
|
@ -563,8 +562,7 @@ static int test__basic_mmap(void)
|
|||
goto out_munmap;
|
||||
}
|
||||
|
||||
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
|
||||
false, &sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample, false);
|
||||
if (err) {
|
||||
pr_err("Can't parse sample, err = %d\n", err);
|
||||
goto out_munmap;
|
||||
|
@ -661,12 +659,12 @@ static int test__PERF_RECORD(void)
|
|||
const char *cmd = "sleep";
|
||||
const char *argv[] = { cmd, "1", NULL, };
|
||||
char *bname;
|
||||
u64 sample_type, prev_time = 0;
|
||||
u64 prev_time = 0;
|
||||
bool found_cmd_mmap = false,
|
||||
found_libc_mmap = false,
|
||||
found_vdso_mmap = false,
|
||||
found_ld_mmap = false;
|
||||
int err = -1, errs = 0, i, wakeups = 0, sample_size;
|
||||
int err = -1, errs = 0, i, wakeups = 0;
|
||||
u32 cpu;
|
||||
int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
|
||||
|
||||
|
@ -756,13 +754,6 @@ static int test__PERF_RECORD(void)
|
|||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
/*
|
||||
* We'll need these two to parse the PERF_SAMPLE_* fields in each
|
||||
* event.
|
||||
*/
|
||||
sample_type = perf_evlist__sample_type(evlist);
|
||||
sample_size = __perf_evsel__sample_size(sample_type);
|
||||
|
||||
/*
|
||||
* Now that all is properly set up, enable the events, they will
|
||||
* count just on workload.pid, which will start...
|
||||
|
@ -788,9 +779,7 @@ static int test__PERF_RECORD(void)
|
|||
if (type < PERF_RECORD_MAX)
|
||||
nr_events[type]++;
|
||||
|
||||
err = perf_event__parse_sample(event, sample_type,
|
||||
sample_size, true,
|
||||
&sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample, false);
|
||||
if (err < 0) {
|
||||
if (verbose)
|
||||
perf_event__fprintf(event, stderr);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "util/cpumap.h"
|
||||
#include "util/xyarray.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/intlist.h"
|
||||
|
||||
#include "util/debug.h"
|
||||
|
||||
|
@ -706,8 +707,16 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
|||
int err;
|
||||
|
||||
if (!machine && perf_guest) {
|
||||
pr_err("Can't find guest [%d]'s kernel information\n",
|
||||
event->ip.pid);
|
||||
static struct intlist *seen;
|
||||
|
||||
if (!seen)
|
||||
seen = intlist__new();
|
||||
|
||||
if (!intlist__has_entry(seen, event->ip.pid)) {
|
||||
pr_err("Can't find guest [%d]'s kernel information\n",
|
||||
event->ip.pid);
|
||||
intlist__add(seen, event->ip.pid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -811,7 +820,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
|
|||
int ret;
|
||||
|
||||
while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
|
||||
ret = perf_session__parse_sample(session, event, &sample);
|
||||
ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
|
||||
if (ret) {
|
||||
pr_err("Can't parse sample, err = %d\n", ret);
|
||||
continue;
|
||||
|
@ -943,8 +952,10 @@ try_again:
|
|||
* based cpu-clock-tick sw counter, which
|
||||
* is always available even if no PMU support:
|
||||
*/
|
||||
if (attr->type == PERF_TYPE_HARDWARE &&
|
||||
attr->config == PERF_COUNT_HW_CPU_CYCLES) {
|
||||
if ((err == ENOENT || err == ENXIO) &&
|
||||
(attr->type == PERF_TYPE_HARDWARE) &&
|
||||
(attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
|
||||
|
||||
if (verbose)
|
||||
ui__warning("Cycles event not supported,\n"
|
||||
"trying to fall back to cpu-clock-ticks\n");
|
||||
|
@ -1032,7 +1043,7 @@ static int __cmd_top(struct perf_top *top)
|
|||
&top->session->host_machine);
|
||||
perf_top__start_counters(top);
|
||||
top->session->evlist = top->evlist;
|
||||
perf_session__update_sample_type(top->session);
|
||||
perf_session__set_id_hdr_size(top->session);
|
||||
|
||||
/* Wait for a minimal set of events before starting the snapshot */
|
||||
poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
|
||||
|
|
|
@ -197,9 +197,6 @@ int perf_event__preprocess_sample(const union perf_event *self,
|
|||
|
||||
const char *perf_event__name(unsigned int id);
|
||||
|
||||
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||
int sample_size, bool sample_id_all,
|
||||
struct perf_sample *sample, bool swapped);
|
||||
int perf_event__synthesize_sample(union perf_event *event, u64 type,
|
||||
const struct perf_sample *sample,
|
||||
bool swapped);
|
||||
|
|
|
@ -881,3 +881,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped)
|
||||
{
|
||||
struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||
return perf_evsel__parse_sample(e, event, sample, swapped);
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
|
|||
bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
|
||||
u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
|
||||
|
||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped);
|
||||
|
||||
bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
|
||||
bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
||||
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
|
||||
|
||||
int __perf_evsel__sample_size(u64 sample_type)
|
||||
static int __perf_evsel__sample_size(u64 sample_type)
|
||||
{
|
||||
u64 mask = sample_type & PERF_SAMPLE_MASK;
|
||||
int size = 0;
|
||||
|
@ -53,6 +53,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
|
|||
evsel->attr = *attr;
|
||||
INIT_LIST_HEAD(&evsel->node);
|
||||
hists__init(&evsel->hists);
|
||||
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
|
||||
}
|
||||
|
||||
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
|
||||
|
@ -728,10 +729,10 @@ static bool sample_overlap(const union perf_event *event,
|
|||
return false;
|
||||
}
|
||||
|
||||
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||
int sample_size, bool sample_id_all,
|
||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *data, bool swapped)
|
||||
{
|
||||
u64 type = evsel->attr.sample_type;
|
||||
const u64 *array;
|
||||
|
||||
/*
|
||||
|
@ -746,14 +747,14 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
|||
data->period = 1;
|
||||
|
||||
if (event->header.type != PERF_RECORD_SAMPLE) {
|
||||
if (!sample_id_all)
|
||||
if (!evsel->attr.sample_id_all)
|
||||
return 0;
|
||||
return perf_event__parse_id_sample(event, type, data, swapped);
|
||||
}
|
||||
|
||||
array = event->sample.array;
|
||||
|
||||
if (sample_size + sizeof(event->header) > event->header.size)
|
||||
if (evsel->sample_size + sizeof(event->header) > event->header.size)
|
||||
return -EFAULT;
|
||||
|
||||
if (type & PERF_SAMPLE_IP) {
|
||||
|
@ -895,7 +896,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
|
|||
u.val32[1] = sample->tid;
|
||||
if (swapped) {
|
||||
/*
|
||||
* Inverse of what is done in perf_event__parse_sample
|
||||
* Inverse of what is done in perf_evsel__parse_sample
|
||||
*/
|
||||
u.val32[0] = bswap_32(u.val32[0]);
|
||||
u.val32[1] = bswap_32(u.val32[1]);
|
||||
|
@ -930,7 +931,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
|
|||
u.val32[0] = sample->cpu;
|
||||
if (swapped) {
|
||||
/*
|
||||
* Inverse of what is done in perf_event__parse_sample
|
||||
* Inverse of what is done in perf_evsel__parse_sample
|
||||
*/
|
||||
u.val32[0] = bswap_32(u.val32[0]);
|
||||
u.val64 = bswap_64(u.val64);
|
||||
|
|
|
@ -65,6 +65,7 @@ struct perf_evsel {
|
|||
void *func;
|
||||
void *data;
|
||||
} handler;
|
||||
unsigned int sample_size;
|
||||
bool supported;
|
||||
};
|
||||
|
||||
|
@ -177,13 +178,8 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
|
|||
return __perf_evsel__read(evsel, ncpus, nthreads, true);
|
||||
}
|
||||
|
||||
int __perf_evsel__sample_size(u64 sample_type);
|
||||
|
||||
static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
|
||||
{
|
||||
return __perf_evsel__sample_size(evsel->attr.sample_type);
|
||||
}
|
||||
|
||||
void hists__init(struct hists *hists);
|
||||
|
||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped);
|
||||
#endif /* __PERF_EVSEL_H */
|
||||
|
|
|
@ -174,6 +174,15 @@ perf_header__set_cmdline(int argc, const char **argv)
|
|||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If header_argv has already been set, do not override it.
|
||||
* This allows a command to set the cmdline, parse args and
|
||||
* then call another builtin function that implements a
|
||||
* command -- e.g, cmd_kvm calling cmd_record.
|
||||
*/
|
||||
if (header_argv)
|
||||
return 0;
|
||||
|
||||
header_argc = (u32)argc;
|
||||
|
||||
/* do not include NULL termination */
|
||||
|
|
101
tools/perf/util/intlist.c
Normal file
101
tools/perf/util/intlist.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Based on intlist.c by:
|
||||
* (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*
|
||||
* Licensed under the GPLv2.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "intlist.h"
|
||||
|
||||
static struct rb_node *intlist__node_new(struct rblist *rblist __used,
|
||||
const void *entry)
|
||||
{
|
||||
int i = (int)((long)entry);
|
||||
struct rb_node *rc = NULL;
|
||||
struct int_node *node = malloc(sizeof(*node));
|
||||
|
||||
if (node != NULL) {
|
||||
node->i = i;
|
||||
rc = &node->rb_node;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void int_node__delete(struct int_node *ilist)
|
||||
{
|
||||
free(ilist);
|
||||
}
|
||||
|
||||
static void intlist__node_delete(struct rblist *rblist __used,
|
||||
struct rb_node *rb_node)
|
||||
{
|
||||
struct int_node *node = container_of(rb_node, struct int_node, rb_node);
|
||||
|
||||
int_node__delete(node);
|
||||
}
|
||||
|
||||
static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
|
||||
{
|
||||
int i = (int)((long)entry);
|
||||
struct int_node *node = container_of(rb_node, struct int_node, rb_node);
|
||||
|
||||
return node->i - i;
|
||||
}
|
||||
|
||||
int intlist__add(struct intlist *ilist, int i)
|
||||
{
|
||||
return rblist__add_node(&ilist->rblist, (void *)((long)i));
|
||||
}
|
||||
|
||||
void intlist__remove(struct intlist *ilist __used, struct int_node *node)
|
||||
{
|
||||
int_node__delete(node);
|
||||
}
|
||||
|
||||
struct int_node *intlist__find(struct intlist *ilist, int i)
|
||||
{
|
||||
struct int_node *node = NULL;
|
||||
struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
|
||||
|
||||
if (rb_node)
|
||||
node = container_of(rb_node, struct int_node, rb_node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct intlist *intlist__new(void)
|
||||
{
|
||||
struct intlist *ilist = malloc(sizeof(*ilist));
|
||||
|
||||
if (ilist != NULL) {
|
||||
rblist__init(&ilist->rblist);
|
||||
ilist->rblist.node_cmp = intlist__node_cmp;
|
||||
ilist->rblist.node_new = intlist__node_new;
|
||||
ilist->rblist.node_delete = intlist__node_delete;
|
||||
}
|
||||
|
||||
return ilist;
|
||||
}
|
||||
|
||||
void intlist__delete(struct intlist *ilist)
|
||||
{
|
||||
if (ilist != NULL)
|
||||
rblist__delete(&ilist->rblist);
|
||||
}
|
||||
|
||||
struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
|
||||
{
|
||||
struct int_node *node = NULL;
|
||||
struct rb_node *rb_node;
|
||||
|
||||
rb_node = rblist__entry(&ilist->rblist, idx);
|
||||
if (rb_node)
|
||||
node = container_of(rb_node, struct int_node, rb_node);
|
||||
|
||||
return node;
|
||||
}
|
75
tools/perf/util/intlist.h
Normal file
75
tools/perf/util/intlist.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
#ifndef __PERF_INTLIST_H
|
||||
#define __PERF_INTLIST_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rblist.h"
|
||||
|
||||
struct int_node {
|
||||
struct rb_node rb_node;
|
||||
int i;
|
||||
};
|
||||
|
||||
struct intlist {
|
||||
struct rblist rblist;
|
||||
};
|
||||
|
||||
struct intlist *intlist__new(void);
|
||||
void intlist__delete(struct intlist *ilist);
|
||||
|
||||
void intlist__remove(struct intlist *ilist, struct int_node *in);
|
||||
int intlist__add(struct intlist *ilist, int i);
|
||||
|
||||
struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
|
||||
struct int_node *intlist__find(struct intlist *ilist, int i);
|
||||
|
||||
static inline bool intlist__has_entry(struct intlist *ilist, int i)
|
||||
{
|
||||
return intlist__find(ilist, i) != NULL;
|
||||
}
|
||||
|
||||
static inline bool intlist__empty(const struct intlist *ilist)
|
||||
{
|
||||
return rblist__empty(&ilist->rblist);
|
||||
}
|
||||
|
||||
static inline unsigned int intlist__nr_entries(const struct intlist *ilist)
|
||||
{
|
||||
return rblist__nr_entries(&ilist->rblist);
|
||||
}
|
||||
|
||||
/* For intlist iteration */
|
||||
static inline struct int_node *intlist__first(struct intlist *ilist)
|
||||
{
|
||||
struct rb_node *rn = rb_first(&ilist->rblist.entries);
|
||||
return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
|
||||
}
|
||||
static inline struct int_node *intlist__next(struct int_node *in)
|
||||
{
|
||||
struct rb_node *rn;
|
||||
if (!in)
|
||||
return NULL;
|
||||
rn = rb_next(&in->rb_node);
|
||||
return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* intlist_for_each - iterate over a intlist
|
||||
* @pos: the &struct int_node to use as a loop cursor.
|
||||
* @ilist: the &struct intlist for loop.
|
||||
*/
|
||||
#define intlist__for_each(pos, ilist) \
|
||||
for (pos = intlist__first(ilist); pos; pos = intlist__next(pos))
|
||||
|
||||
/**
|
||||
* intlist_for_each_safe - iterate over a intlist safe against removal of
|
||||
* int_node
|
||||
* @pos: the &struct int_node to use as a loop cursor.
|
||||
* @n: another &struct int_node to use as temporary storage.
|
||||
* @ilist: the &struct intlist for loop.
|
||||
*/
|
||||
#define intlist__for_each_safe(pos, n, ilist) \
|
||||
for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\
|
||||
pos = n, n = intlist__next(n))
|
||||
#endif /* __PERF_INTLIST_H */
|
|
@ -13,6 +13,9 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
|
||||
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
|
||||
|
||||
static int test__checkevent_tracepoint(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
|
@ -21,8 +24,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
|
|||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong sample_type",
|
||||
(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
|
||||
evsel->attr.sample_type);
|
||||
PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
|
||||
TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
|
||||
return 0;
|
||||
}
|
||||
|
@ -37,8 +39,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
|
|||
TEST_ASSERT_VAL("wrong type",
|
||||
PERF_TYPE_TRACEPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong sample_type",
|
||||
(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
|
||||
== evsel->attr.sample_type);
|
||||
PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
|
||||
TEST_ASSERT_VAL("wrong sample_period",
|
||||
1 == evsel->attr.sample_period);
|
||||
}
|
||||
|
@ -428,8 +429,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
|
|||
evsel = list_entry(evsel->node.next, struct perf_evsel, node);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong sample_type",
|
||||
(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
|
||||
evsel->attr.sample_type);
|
||||
PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
|
||||
TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
|
||||
TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
|
||||
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "util.h"
|
||||
#include "parse-options.h"
|
||||
#include "cache.h"
|
||||
#include "header.h"
|
||||
|
||||
#define OPT_SHORT 1
|
||||
#define OPT_UNSET 2
|
||||
|
@ -413,6 +414,8 @@ int parse_options(int argc, const char **argv, const struct option *options,
|
|||
{
|
||||
struct parse_opt_ctx_t ctx;
|
||||
|
||||
perf_header__set_cmdline(argc, argv);
|
||||
|
||||
parse_options_start(&ctx, argc, argv, flags);
|
||||
switch (parse_options_step(&ctx, options, usagestr)) {
|
||||
case PARSE_OPT_HELP:
|
||||
|
|
|
@ -797,17 +797,13 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
|||
|
||||
event = perf_evlist__mmap_read(evlist, cpu);
|
||||
if (event != NULL) {
|
||||
struct perf_evsel *first;
|
||||
PyObject *pyevent = pyrf_event__new(event);
|
||||
struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
|
||||
|
||||
if (pyevent == NULL)
|
||||
return PyErr_NoMemory();
|
||||
|
||||
first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||
err = perf_event__parse_sample(event, first->attr.sample_type,
|
||||
perf_evsel__sample_size(first),
|
||||
sample_id_all, &pevent->sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
|
||||
if (err)
|
||||
return PyErr_Format(PyExc_OSError,
|
||||
"perf: can't parse sample, err=%d", err);
|
||||
|
|
107
tools/perf/util/rblist.c
Normal file
107
tools/perf/util/rblist.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Based on strlist.c by:
|
||||
* (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*
|
||||
* Licensed under the GPLv2.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rblist.h"
|
||||
|
||||
int rblist__add_node(struct rblist *rblist, const void *new_entry)
|
||||
{
|
||||
struct rb_node **p = &rblist->entries.rb_node;
|
||||
struct rb_node *parent = NULL, *new_node;
|
||||
|
||||
while (*p != NULL) {
|
||||
int rc;
|
||||
|
||||
parent = *p;
|
||||
|
||||
rc = rblist->node_cmp(parent, new_entry);
|
||||
if (rc > 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (rc < 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
new_node = rblist->node_new(rblist, new_entry);
|
||||
if (new_node == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rb_link_node(new_node, parent, p);
|
||||
rb_insert_color(new_node, &rblist->entries);
|
||||
++rblist->nr_entries;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
|
||||
{
|
||||
rb_erase(rb_node, &rblist->entries);
|
||||
rblist->node_delete(rblist, rb_node);
|
||||
}
|
||||
|
||||
struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
|
||||
{
|
||||
struct rb_node **p = &rblist->entries.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
|
||||
while (*p != NULL) {
|
||||
int rc;
|
||||
|
||||
parent = *p;
|
||||
|
||||
rc = rblist->node_cmp(parent, entry);
|
||||
if (rc > 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (rc < 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return parent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rblist__init(struct rblist *rblist)
|
||||
{
|
||||
if (rblist != NULL) {
|
||||
rblist->entries = RB_ROOT;
|
||||
rblist->nr_entries = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void rblist__delete(struct rblist *rblist)
|
||||
{
|
||||
if (rblist != NULL) {
|
||||
struct rb_node *pos, *next = rb_first(&rblist->entries);
|
||||
|
||||
while (next) {
|
||||
pos = next;
|
||||
next = rb_next(pos);
|
||||
rb_erase(pos, &rblist->entries);
|
||||
rblist->node_delete(rblist, pos);
|
||||
}
|
||||
free(rblist);
|
||||
}
|
||||
}
|
||||
|
||||
struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
|
||||
{
|
||||
struct rb_node *node;
|
||||
|
||||
for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {
|
||||
if (!idx--)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
47
tools/perf/util/rblist.h
Normal file
47
tools/perf/util/rblist.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef __PERF_RBLIST_H
|
||||
#define __PERF_RBLIST_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* create node structs of the form:
|
||||
* struct my_node {
|
||||
* struct rb_node rb_node;
|
||||
* ... my data ...
|
||||
* };
|
||||
*
|
||||
* create list structs of the form:
|
||||
* struct mylist {
|
||||
* struct rblist rblist;
|
||||
* ... my data ...
|
||||
* };
|
||||
*/
|
||||
|
||||
struct rblist {
|
||||
struct rb_root entries;
|
||||
unsigned int nr_entries;
|
||||
|
||||
int (*node_cmp)(struct rb_node *rbn, const void *entry);
|
||||
struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);
|
||||
void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);
|
||||
};
|
||||
|
||||
void rblist__init(struct rblist *rblist);
|
||||
void rblist__delete(struct rblist *rblist);
|
||||
int rblist__add_node(struct rblist *rblist, const void *new_entry);
|
||||
void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
|
||||
struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
|
||||
struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
|
||||
|
||||
static inline bool rblist__empty(const struct rblist *rblist)
|
||||
{
|
||||
return rblist->nr_entries == 0;
|
||||
}
|
||||
|
||||
static inline unsigned int rblist__nr_entries(const struct rblist *rblist)
|
||||
{
|
||||
return rblist->nr_entries;
|
||||
}
|
||||
|
||||
#endif /* __PERF_RBLIST_H */
|
|
@ -80,14 +80,12 @@ out_close:
|
|||
return -1;
|
||||
}
|
||||
|
||||
void perf_session__update_sample_type(struct perf_session *self)
|
||||
void perf_session__set_id_hdr_size(struct perf_session *session)
|
||||
{
|
||||
self->sample_type = perf_evlist__sample_type(self->evlist);
|
||||
self->sample_size = __perf_evsel__sample_size(self->sample_type);
|
||||
self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
|
||||
self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
|
||||
self->host_machine.id_hdr_size = self->id_hdr_size;
|
||||
machines__set_id_hdr_size(&self->machines, self->id_hdr_size);
|
||||
u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
|
||||
|
||||
session->host_machine.id_hdr_size = id_hdr_size;
|
||||
machines__set_id_hdr_size(&session->machines, id_hdr_size);
|
||||
}
|
||||
|
||||
int perf_session__create_kernel_maps(struct perf_session *self)
|
||||
|
@ -147,7 +145,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
|
|||
if (mode == O_RDONLY) {
|
||||
if (perf_session__open(self, force) < 0)
|
||||
goto out_delete;
|
||||
perf_session__update_sample_type(self);
|
||||
perf_session__set_id_hdr_size(self);
|
||||
} else if (mode == O_WRONLY) {
|
||||
/*
|
||||
* In O_RDONLY mode this will be performed when reading the
|
||||
|
@ -158,7 +156,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
|
|||
}
|
||||
|
||||
if (tool && tool->ordering_requires_timestamps &&
|
||||
tool->ordered_samples && !self->sample_id_all) {
|
||||
tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) {
|
||||
dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
|
||||
tool->ordered_samples = false;
|
||||
}
|
||||
|
@ -673,7 +671,8 @@ static void flush_sample_queue(struct perf_session *s,
|
|||
if (iter->timestamp > limit)
|
||||
break;
|
||||
|
||||
ret = perf_session__parse_sample(s, iter->event, &sample);
|
||||
ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
|
||||
s->header.needs_swap);
|
||||
if (ret)
|
||||
pr_err("Can't parse sample, err = %d\n", ret);
|
||||
else
|
||||
|
@ -865,16 +864,18 @@ static void perf_session__print_tstamp(struct perf_session *session,
|
|||
union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
u64 sample_type = perf_evlist__sample_type(session->evlist);
|
||||
|
||||
if (event->header.type != PERF_RECORD_SAMPLE &&
|
||||
!session->sample_id_all) {
|
||||
!perf_evlist__sample_id_all(session->evlist)) {
|
||||
fputs("-1 -1 ", stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((session->sample_type & PERF_SAMPLE_CPU))
|
||||
if ((sample_type & PERF_SAMPLE_CPU))
|
||||
printf("%u ", sample->cpu);
|
||||
|
||||
if (session->sample_type & PERF_SAMPLE_TIME)
|
||||
if (sample_type & PERF_SAMPLE_TIME)
|
||||
printf("%" PRIu64 " ", sample->time);
|
||||
}
|
||||
|
||||
|
@ -899,6 +900,8 @@ static void dump_event(struct perf_session *session, union perf_event *event,
|
|||
static void dump_sample(struct perf_session *session, union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
u64 sample_type;
|
||||
|
||||
if (!dump_trace)
|
||||
return;
|
||||
|
||||
|
@ -906,10 +909,12 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
|
|||
event->header.misc, sample->pid, sample->tid, sample->ip,
|
||||
sample->period, sample->addr);
|
||||
|
||||
if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
|
||||
sample_type = perf_evlist__sample_type(session->evlist);
|
||||
|
||||
if (sample_type & PERF_SAMPLE_CALLCHAIN)
|
||||
callchain__printf(sample);
|
||||
|
||||
if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
|
||||
if (sample_type & PERF_SAMPLE_BRANCH_STACK)
|
||||
branch_stack__printf(sample);
|
||||
}
|
||||
|
||||
|
@ -1006,7 +1011,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
|
|||
union perf_event *event, struct perf_sample *sample)
|
||||
{
|
||||
if (event->header.type != PERF_RECORD_SAMPLE ||
|
||||
!(session->sample_type & PERF_SAMPLE_CALLCHAIN))
|
||||
!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
|
||||
return 0;
|
||||
|
||||
if (!ip_callchain__valid(sample->callchain, event)) {
|
||||
|
@ -1030,7 +1035,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
|
|||
case PERF_RECORD_HEADER_ATTR:
|
||||
err = tool->attr(event, &session->evlist);
|
||||
if (err == 0)
|
||||
perf_session__update_sample_type(session);
|
||||
perf_session__set_id_hdr_size(session);
|
||||
return err;
|
||||
case PERF_RECORD_HEADER_EVENT_TYPE:
|
||||
return tool->event_type(tool, event);
|
||||
|
@ -1065,7 +1070,7 @@ static int perf_session__process_event(struct perf_session *session,
|
|||
int ret;
|
||||
|
||||
if (session->header.needs_swap)
|
||||
event_swap(event, session->sample_id_all);
|
||||
event_swap(event, perf_evlist__sample_id_all(session->evlist));
|
||||
|
||||
if (event->header.type >= PERF_RECORD_HEADER_MAX)
|
||||
return -EINVAL;
|
||||
|
@ -1078,7 +1083,8 @@ static int perf_session__process_event(struct perf_session *session,
|
|||
/*
|
||||
* For all kernel events we get the sample data
|
||||
*/
|
||||
ret = perf_session__parse_sample(session, event, &sample);
|
||||
ret = perf_evlist__parse_sample(session->evlist, event, &sample,
|
||||
session->header.needs_swap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1389,9 +1395,9 @@ int perf_session__process_events(struct perf_session *self,
|
|||
return err;
|
||||
}
|
||||
|
||||
bool perf_session__has_traces(struct perf_session *self, const char *msg)
|
||||
bool perf_session__has_traces(struct perf_session *session, const char *msg)
|
||||
{
|
||||
if (!(self->sample_type & PERF_SAMPLE_RAW)) {
|
||||
if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) {
|
||||
pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -41,13 +41,9 @@ struct perf_session {
|
|||
* perf.data file.
|
||||
*/
|
||||
struct hists hists;
|
||||
u64 sample_type;
|
||||
int sample_size;
|
||||
int fd;
|
||||
bool fd_pipe;
|
||||
bool repipe;
|
||||
bool sample_id_all;
|
||||
u16 id_hdr_size;
|
||||
int cwdlen;
|
||||
char *cwd;
|
||||
struct ordered_samples ordered_samples;
|
||||
|
@ -86,7 +82,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
|
|||
|
||||
int perf_session__create_kernel_maps(struct perf_session *self);
|
||||
|
||||
void perf_session__update_sample_type(struct perf_session *self);
|
||||
void perf_session__set_id_hdr_size(struct perf_session *session);
|
||||
void perf_session__remove_thread(struct perf_session *self, struct thread *th);
|
||||
|
||||
static inline
|
||||
|
@ -130,24 +126,6 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
|
|||
|
||||
size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
|
||||
|
||||
static inline int perf_session__parse_sample(struct perf_session *session,
|
||||
const union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
return perf_event__parse_sample(event, session->sample_type,
|
||||
session->sample_size,
|
||||
session->sample_id_all, sample,
|
||||
session->header.needs_swap);
|
||||
}
|
||||
|
||||
static inline int perf_session__synthesize_sample(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
const struct perf_sample *sample)
|
||||
{
|
||||
return perf_event__synthesize_sample(event, session->sample_type,
|
||||
sample, session->header.needs_swap);
|
||||
}
|
||||
|
||||
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||
unsigned int type);
|
||||
|
||||
|
|
|
@ -10,23 +10,28 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct str_node *str_node__new(const char *s, bool dupstr)
|
||||
static
|
||||
struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
|
||||
{
|
||||
struct str_node *self = malloc(sizeof(*self));
|
||||
const char *s = entry;
|
||||
struct rb_node *rc = NULL;
|
||||
struct strlist *strlist = container_of(rblist, struct strlist, rblist);
|
||||
struct str_node *snode = malloc(sizeof(*snode));
|
||||
|
||||
if (self != NULL) {
|
||||
if (dupstr) {
|
||||
if (snode != NULL) {
|
||||
if (strlist->dupstr) {
|
||||
s = strdup(s);
|
||||
if (s == NULL)
|
||||
goto out_delete;
|
||||
}
|
||||
self->s = s;
|
||||
snode->s = s;
|
||||
rc = &snode->rb_node;
|
||||
}
|
||||
|
||||
return self;
|
||||
return rc;
|
||||
|
||||
out_delete:
|
||||
free(self);
|
||||
free(snode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -37,36 +42,26 @@ static void str_node__delete(struct str_node *self, bool dupstr)
|
|||
free(self);
|
||||
}
|
||||
|
||||
static
|
||||
void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
|
||||
{
|
||||
struct strlist *slist = container_of(rblist, struct strlist, rblist);
|
||||
struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
|
||||
|
||||
str_node__delete(snode, slist->dupstr);
|
||||
}
|
||||
|
||||
static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
|
||||
{
|
||||
const char *str = entry;
|
||||
struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
|
||||
|
||||
return strcmp(snode->s, str);
|
||||
}
|
||||
|
||||
int strlist__add(struct strlist *self, const char *new_entry)
|
||||
{
|
||||
struct rb_node **p = &self->entries.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct str_node *sn;
|
||||
|
||||
while (*p != NULL) {
|
||||
int rc;
|
||||
|
||||
parent = *p;
|
||||
sn = rb_entry(parent, struct str_node, rb_node);
|
||||
rc = strcmp(sn->s, new_entry);
|
||||
|
||||
if (rc > 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (rc < 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
sn = str_node__new(new_entry, self->dupstr);
|
||||
if (sn == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rb_link_node(&sn->rb_node, parent, p);
|
||||
rb_insert_color(&sn->rb_node, &self->entries);
|
||||
++self->nr_entries;
|
||||
|
||||
return 0;
|
||||
return rblist__add_node(&self->rblist, new_entry);
|
||||
}
|
||||
|
||||
int strlist__load(struct strlist *self, const char *filename)
|
||||
|
@ -96,34 +91,20 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
void strlist__remove(struct strlist *self, struct str_node *sn)
|
||||
void strlist__remove(struct strlist *slist, struct str_node *snode)
|
||||
{
|
||||
rb_erase(&sn->rb_node, &self->entries);
|
||||
str_node__delete(sn, self->dupstr);
|
||||
str_node__delete(snode, slist->dupstr);
|
||||
}
|
||||
|
||||
struct str_node *strlist__find(struct strlist *self, const char *entry)
|
||||
struct str_node *strlist__find(struct strlist *slist, const char *entry)
|
||||
{
|
||||
struct rb_node **p = &self->entries.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct str_node *snode = NULL;
|
||||
struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
|
||||
|
||||
while (*p != NULL) {
|
||||
struct str_node *sn;
|
||||
int rc;
|
||||
if (rb_node)
|
||||
snode = container_of(rb_node, struct str_node, rb_node);
|
||||
|
||||
parent = *p;
|
||||
sn = rb_entry(parent, struct str_node, rb_node);
|
||||
rc = strcmp(sn->s, entry);
|
||||
|
||||
if (rc > 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (rc < 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return sn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return snode;
|
||||
}
|
||||
|
||||
static int strlist__parse_list_entry(struct strlist *self, const char *s)
|
||||
|
@ -156,9 +137,12 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
|
|||
struct strlist *self = malloc(sizeof(*self));
|
||||
|
||||
if (self != NULL) {
|
||||
self->entries = RB_ROOT;
|
||||
rblist__init(&self->rblist);
|
||||
self->rblist.node_cmp = strlist__node_cmp;
|
||||
self->rblist.node_new = strlist__node_new;
|
||||
self->rblist.node_delete = strlist__node_delete;
|
||||
|
||||
self->dupstr = dupstr;
|
||||
self->nr_entries = 0;
|
||||
if (slist && strlist__parse_list(self, slist) != 0)
|
||||
goto out_error;
|
||||
}
|
||||
|
@ -171,30 +155,18 @@ out_error:
|
|||
|
||||
void strlist__delete(struct strlist *self)
|
||||
{
|
||||
if (self != NULL) {
|
||||
struct str_node *pos;
|
||||
struct rb_node *next = rb_first(&self->entries);
|
||||
|
||||
while (next) {
|
||||
pos = rb_entry(next, struct str_node, rb_node);
|
||||
next = rb_next(&pos->rb_node);
|
||||
strlist__remove(self, pos);
|
||||
}
|
||||
self->entries = RB_ROOT;
|
||||
free(self);
|
||||
}
|
||||
if (self != NULL)
|
||||
rblist__delete(&self->rblist);
|
||||
}
|
||||
|
||||
struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
|
||||
struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
struct str_node *snode = NULL;
|
||||
struct rb_node *rb_node;
|
||||
|
||||
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
|
||||
struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
|
||||
rb_node = rblist__entry(&slist->rblist, idx);
|
||||
if (rb_node)
|
||||
snode = container_of(rb_node, struct str_node, rb_node);
|
||||
|
||||
if (!idx--)
|
||||
return pos;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return snode;
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
#include <linux/rbtree.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rblist.h"
|
||||
|
||||
struct str_node {
|
||||
struct rb_node rb_node;
|
||||
const char *s;
|
||||
};
|
||||
|
||||
struct strlist {
|
||||
struct rb_root entries;
|
||||
unsigned int nr_entries;
|
||||
struct rblist rblist;
|
||||
bool dupstr;
|
||||
};
|
||||
|
||||
|
@ -32,18 +33,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry)
|
|||
|
||||
static inline bool strlist__empty(const struct strlist *self)
|
||||
{
|
||||
return self->nr_entries == 0;
|
||||
return rblist__empty(&self->rblist);
|
||||
}
|
||||
|
||||
static inline unsigned int strlist__nr_entries(const struct strlist *self)
|
||||
{
|
||||
return self->nr_entries;
|
||||
return rblist__nr_entries(&self->rblist);
|
||||
}
|
||||
|
||||
/* For strlist iteration */
|
||||
static inline struct str_node *strlist__first(struct strlist *self)
|
||||
{
|
||||
struct rb_node *rn = rb_first(&self->entries);
|
||||
struct rb_node *rn = rb_first(&self->rblist.entries);
|
||||
return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
|
||||
}
|
||||
static inline struct str_node *strlist__next(struct str_node *sn)
|
||||
|
|
|
@ -64,7 +64,7 @@ static enum dso_binary_type binary_type_symtab[] = {
|
|||
DSO_BINARY_TYPE__NOT_FOUND,
|
||||
};
|
||||
|
||||
#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
|
||||
#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
|
||||
|
||||
static enum dso_binary_type binary_type_data[] = {
|
||||
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
||||
|
@ -72,7 +72,7 @@ static enum dso_binary_type binary_type_data[] = {
|
|||
DSO_BINARY_TYPE__NOT_FOUND,
|
||||
};
|
||||
|
||||
#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
|
||||
#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
|
||||
|
||||
int dso__name_len(const struct dso *dso)
|
||||
{
|
||||
|
@ -2875,6 +2875,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
|
|||
int i, items = 0;
|
||||
char path[PATH_MAX];
|
||||
pid_t pid;
|
||||
char *endp;
|
||||
|
||||
if (symbol_conf.default_guest_vmlinux_name ||
|
||||
symbol_conf.default_guest_modules ||
|
||||
|
@ -2891,7 +2892,14 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
|
|||
/* Filter out . and .. */
|
||||
continue;
|
||||
}
|
||||
pid = atoi(namelist[i]->d_name);
|
||||
pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
|
||||
if ((*endp != '\0') ||
|
||||
(endp == namelist[i]->d_name) ||
|
||||
(errno == ERANGE)) {
|
||||
pr_debug("invalid directory (%s). Skipping.\n",
|
||||
namelist[i]->d_name);
|
||||
continue;
|
||||
}
|
||||
sprintf(path, "%s/%s/proc/kallsyms",
|
||||
symbol_conf.guestmount,
|
||||
namelist[i]->d_name);
|
||||
|
|
|
@ -110,7 +110,7 @@ int perf_target__strerror(struct perf_target *target, int errnum,
|
|||
int idx;
|
||||
const char *msg;
|
||||
|
||||
BUG_ON(buflen > 0);
|
||||
BUG_ON(buflen == 0);
|
||||
|
||||
if (errnum >= 0) {
|
||||
const char *err = strerror_r(errnum, buf, buflen);
|
||||
|
|
Loading…
Reference in a new issue