Commit c2b8d8c5 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo-2' of...

Merge tag 'perf-core-for-mingo-2' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

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

New features:

  - Add API to set values of map entries in a BPF object, be it
    individual map slots or ranges (Wang Nan)

  - Introduce support for the 'bpf-output' event (Wang Nan)

  - Add glue to read perf events in a BPF program (Wang Nan)

User visible changes:

  - Don't stop PMU parsing on alias parse error, allowing the
    addition of new sysfs PMU files without breaking old tools (Andi Kleen)

  - Implement '%' operation in libtraceevent (Daniel Bristot de Oliveira)

  - Allow specifying events via -e in 'perf mem record', also listing what events
    can be specified via 'perf mem record -e list' (Jiri Olsa)

  - Improve support to 'data_src', 'weight' and 'addr' fields in
    'perf script' (Jiri Olsa)

Infrastructure changes:

  - Export cacheline routines (Jiri Olsa)

  - Remove strbuf_{remove,splice}(), dead code (Arnaldo Carvalho de Melo)

Fixes:

  - Sort key fixes: Alignment for srcline, file, trace; fix
    segfault for dynamic, trace events related sort keys (Namyung Kim)

Build fixes:

  - Remove duplicate typedef config_term_func_t definition,
    fixing the build on older systems (Arnaldo Carvalho de Melo)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 91e48b7d bea24006
...@@ -1951,6 +1951,7 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok) ...@@ -1951,6 +1951,7 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
strcmp(token, "*") == 0 || strcmp(token, "*") == 0 ||
strcmp(token, "^") == 0 || strcmp(token, "^") == 0 ||
strcmp(token, "/") == 0 || strcmp(token, "/") == 0 ||
strcmp(token, "%") == 0 ||
strcmp(token, "<") == 0 || strcmp(token, "<") == 0 ||
strcmp(token, ">") == 0 || strcmp(token, ">") == 0 ||
strcmp(token, "<=") == 0 || strcmp(token, "<=") == 0 ||
...@@ -3689,6 +3690,9 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg ...@@ -3689,6 +3690,9 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
case '/': case '/':
val = left / right; val = left / right;
break; break;
case '%':
val = left % right;
break;
case '*': case '*':
val = left * right; val = left * right;
break; break;
......
...@@ -86,8 +86,7 @@ static int check_emacsclient_version(void) ...@@ -86,8 +86,7 @@ static int check_emacsclient_version(void)
return -1; return -1;
} }
strbuf_remove(&buffer, 0, strlen("emacsclient")); version = atoi(buffer.buf + strlen("emacsclient"));
version = atoi(buffer.buf);
if (version < 22) { if (version < 22) {
fprintf(stderr, fprintf(stderr,
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "util/tool.h" #include "util/tool.h"
#include "util/session.h" #include "util/session.h"
#include "util/data.h" #include "util/data.h"
#include "util/mem-events.h"
#include "util/debug.h"
#define MEM_OPERATION_LOAD 0x1 #define MEM_OPERATION_LOAD 0x1
#define MEM_OPERATION_STORE 0x2 #define MEM_OPERATION_STORE 0x2
...@@ -21,11 +23,55 @@ struct perf_mem { ...@@ -21,11 +23,55 @@ struct perf_mem {
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
}; };
static int parse_record_events(const struct option *opt,
const char *str, int unset __maybe_unused)
{
struct perf_mem *mem = *(struct perf_mem **)opt->value;
int j;
if (strcmp(str, "list")) {
if (!perf_mem_events__parse(str)) {
mem->operation = 0;
return 0;
}
exit(-1);
}
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
struct perf_mem_event *e = &perf_mem_events[j];
fprintf(stderr, "%-20s%s",
e->tag, verbose ? "" : "\n");
if (verbose)
fprintf(stderr, " [%s]\n", e->name);
}
exit(0);
}
static const char * const __usage[] = {
"perf mem record [<options>] [<command>]",
"perf mem record [<options>] -- <command> [<options>]",
NULL
};
static const char * const *record_mem_usage = __usage;
static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
{ {
int rec_argc, i = 0, j; int rec_argc, i = 0, j;
const char **rec_argv; const char **rec_argv;
int ret; int ret;
struct option options[] = {
OPT_CALLBACK('e', "event", &mem, "event",
"event selector. use 'perf mem record -e list' to list available events",
parse_record_events),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_END()
};
argc = parse_options(argc, argv, options, record_mem_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
rec_argc = argc + 7; /* max number of arguments */ rec_argc = argc + 7; /* max number of arguments */
rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv = calloc(rec_argc + 1, sizeof(char *));
...@@ -35,23 +81,34 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) ...@@ -35,23 +81,34 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
rec_argv[i++] = "record"; rec_argv[i++] = "record";
if (mem->operation & MEM_OPERATION_LOAD) if (mem->operation & MEM_OPERATION_LOAD)
perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
rec_argv[i++] = "-W"; rec_argv[i++] = "-W";
rec_argv[i++] = "-d"; rec_argv[i++] = "-d";
if (mem->operation & MEM_OPERATION_LOAD) { for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
rec_argv[i++] = "-e"; if (!perf_mem_events[j].record)
rec_argv[i++] = "cpu/mem-loads/pp"; continue;
}
if (mem->operation & MEM_OPERATION_STORE) {
rec_argv[i++] = "-e"; rec_argv[i++] = "-e";
rec_argv[i++] = "cpu/mem-stores/pp"; rec_argv[i++] = perf_mem_events[j].name;
} };
for (j = 1; j < argc; j++, i++) for (j = 0; j < argc; j++, i++)
rec_argv[i] = argv[j]; rec_argv[i] = argv[j];
if (verbose > 0) {
pr_debug("calling: record ");
while (rec_argv[j]) {
pr_debug("%s ", rec_argv[j]);
j++;
}
pr_debug("\n");
}
ret = cmd_record(i, rec_argv, NULL); ret = cmd_record(i, rec_argv, NULL);
free(rec_argv); free(rec_argv);
return ret; return ret;
...@@ -298,7 +355,6 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -298,7 +355,6 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
NULL NULL
}; };
argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "util/parse-branch-options.h" #include "util/parse-branch-options.h"
#include "util/parse-regs-options.h" #include "util/parse-regs-options.h"
#include "util/llvm-utils.h" #include "util/llvm-utils.h"
#include "util/bpf-loader.h"
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
...@@ -536,6 +537,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -536,6 +537,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child; goto out_child;
} }
err = bpf__apply_obj_config();
if (err) {
char errbuf[BUFSIZ];
bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
pr_err("ERROR: Apply config to BPF failed: %s\n",
errbuf);
goto out_child;
}
/* /*
* Normally perf_session__new would do this, but it doesn't have the * Normally perf_session__new would do this, but it doesn't have the
* evlist. * evlist.
......
...@@ -58,6 +58,8 @@ enum perf_output_field { ...@@ -58,6 +58,8 @@ enum perf_output_field {
PERF_OUTPUT_IREGS = 1U << 14, PERF_OUTPUT_IREGS = 1U << 14,
PERF_OUTPUT_BRSTACK = 1U << 15, PERF_OUTPUT_BRSTACK = 1U << 15,
PERF_OUTPUT_BRSTACKSYM = 1U << 16, PERF_OUTPUT_BRSTACKSYM = 1U << 16,
PERF_OUTPUT_DATA_SRC = 1U << 17,
PERF_OUTPUT_WEIGHT = 1U << 18,
}; };
struct output_option { struct output_option {
...@@ -81,6 +83,8 @@ struct output_option { ...@@ -81,6 +83,8 @@ struct output_option {
{.str = "iregs", .field = PERF_OUTPUT_IREGS}, {.str = "iregs", .field = PERF_OUTPUT_IREGS},
{.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
{.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
{.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
{.str = "weight", .field = PERF_OUTPUT_WEIGHT},
}; };
/* default set to maintain compatibility with current format */ /* default set to maintain compatibility with current format */
...@@ -131,7 +135,8 @@ static struct { ...@@ -131,7 +135,8 @@ static struct {
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
PERF_OUTPUT_PERIOD, PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT,
.invalid_fields = PERF_OUTPUT_TRACE, .invalid_fields = PERF_OUTPUT_TRACE,
}, },
...@@ -242,6 +247,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, ...@@ -242,6 +247,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
PERF_OUTPUT_ADDR, allow_user_set)) PERF_OUTPUT_ADDR, allow_user_set))
return -EINVAL; return -EINVAL;
if (PRINT_FIELD(DATA_SRC) &&
perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC",
PERF_OUTPUT_DATA_SRC))
return -EINVAL;
if (PRINT_FIELD(WEIGHT) &&
perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT",
PERF_OUTPUT_WEIGHT))
return -EINVAL;
if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
pr_err("Display of symbols requested but neither sample IP nor " pr_err("Display of symbols requested but neither sample IP nor "
"sample address\nis selected. Hence, no addresses to convert " "sample address\nis selected. Hence, no addresses to convert "
...@@ -673,6 +688,12 @@ static void process_event(struct perf_script *script, union perf_event *event, ...@@ -673,6 +688,12 @@ static void process_event(struct perf_script *script, union perf_event *event,
if (PRINT_FIELD(ADDR)) if (PRINT_FIELD(ADDR))
print_sample_addr(event, sample, thread, attr); print_sample_addr(event, sample, thread, attr);
if (PRINT_FIELD(DATA_SRC))
printf("%16" PRIx64, sample->data_src);
if (PRINT_FIELD(WEIGHT))
printf("%16" PRIu64, sample->weight);
if (PRINT_FIELD(IP)) { if (PRINT_FIELD(IP)) {
if (!symbol_conf.use_callchain) if (!symbol_conf.use_callchain)
printf(" "); printf(" ");
......
...@@ -112,7 +112,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), ...@@ -112,7 +112,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
parse_evlist.error = &parse_error; parse_evlist.error = &parse_error;
INIT_LIST_HEAD(&parse_evlist.list); INIT_LIST_HEAD(&parse_evlist.list);
err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj); err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
if (err || list_empty(&parse_evlist.list)) { if (err || list_empty(&parse_evlist.list)) {
pr_debug("Failed to add events selected by BPF\n"); pr_debug("Failed to add events selected by BPF\n");
return TEST_FAIL; return TEST_FAIL;
......
...@@ -645,6 +645,9 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) ...@@ -645,6 +645,9 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
if (perf_hpp__is_sort_entry(fmt)) if (perf_hpp__is_sort_entry(fmt))
return perf_hpp__reset_sort_width(fmt, hists); return perf_hpp__reset_sort_width(fmt, hists);
if (perf_hpp__is_dynamic_entry(fmt))
return;
BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX); BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
switch (fmt->idx) { switch (fmt->idx) {
......
...@@ -82,6 +82,7 @@ libperf-y += parse-branch-options.o ...@@ -82,6 +82,7 @@ libperf-y += parse-branch-options.o
libperf-y += parse-regs-options.o libperf-y += parse-regs-options.o
libperf-y += term.o libperf-y += term.o
libperf-y += help-unknown-cmd.o libperf-y += help-unknown-cmd.o
libperf-y += mem-events.o
libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o
libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <string.h> #include <string.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include "probe-event.h" #include "probe-event.h"
#include "evlist.h"
#include "debug.h" #include "debug.h"
enum bpf_loader_errno { enum bpf_loader_errno {
...@@ -24,10 +25,25 @@ enum bpf_loader_errno { ...@@ -24,10 +25,25 @@ enum bpf_loader_errno {
BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
BPF_LOADER_ERRNO__OBJCONF_OPT, /* Invalid object config option */
BPF_LOADER_ERRNO__OBJCONF_CONF, /* Config value not set (lost '=')) */
BPF_LOADER_ERRNO__OBJCONF_MAP_OPT, /* Invalid object map config option */
BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST, /* Target map not exist */
BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE, /* Incorrect value type for map */
BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, /* Incorrect map type */
BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE, /* Incorrect map key size */
BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */
BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT, /* Event not found for map setting */
BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE, /* Invalid map size for event setting */
BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, /* Event dimension too large */
BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, /* Doesn't support inherit event */
BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, /* Wrong event type for map */
BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */
__BPF_LOADER_ERRNO__END, __BPF_LOADER_ERRNO__END,
}; };
struct bpf_object; struct bpf_object;
struct parse_events_term;
#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" #define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
...@@ -53,6 +69,16 @@ int bpf__strerror_load(struct bpf_object *obj, int err, ...@@ -53,6 +69,16 @@ int bpf__strerror_load(struct bpf_object *obj, int err,
char *buf, size_t size); char *buf, size_t size);
int bpf__foreach_tev(struct bpf_object *obj, int bpf__foreach_tev(struct bpf_object *obj,
bpf_prog_iter_callback_t func, void *arg); bpf_prog_iter_callback_t func, void *arg);
int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term,
struct perf_evlist *evlist, int *error_pos);
int bpf__strerror_config_obj(struct bpf_object *obj,
struct parse_events_term *term,
struct perf_evlist *evlist,
int *error_pos, int err, char *buf,
size_t size);
int bpf__apply_obj_config(void);
int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
#else #else
static inline struct bpf_object * static inline struct bpf_object *
bpf__prepare_load(const char *filename __maybe_unused, bpf__prepare_load(const char *filename __maybe_unused,
...@@ -83,6 +109,21 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused, ...@@ -83,6 +109,21 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
return 0; return 0;
} }
static inline int
bpf__config_obj(struct bpf_object *obj __maybe_unused,
struct parse_events_term *term __maybe_unused,
struct perf_evlist *evlist __maybe_unused,
int *error_pos __maybe_unused)
{
return 0;
}
static inline int
bpf__apply_obj_config(void)
{
return 0;
}
static inline int static inline int
__bpf_strerror(char *buf, size_t size) __bpf_strerror(char *buf, size_t size)
{ {
...@@ -118,5 +159,23 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, ...@@ -118,5 +159,23 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
{ {
return __bpf_strerror(buf, size); return __bpf_strerror(buf, size);
} }
static inline int
bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
struct parse_events_term *term __maybe_unused,
struct perf_evlist *evlist __maybe_unused,
int *error_pos __maybe_unused,
int err __maybe_unused,
char *buf, size_t size)
{
return __bpf_strerror(buf, size);
}
static inline int
bpf__strerror_apply_obj_config(int err __maybe_unused,
char *buf, size_t size)
{
return __bpf_strerror(buf, size);
}
#endif #endif
#endif #endif
...@@ -1741,3 +1741,19 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, ...@@ -1741,3 +1741,19 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
tracking_evsel->tracking = true; tracking_evsel->tracking = true;
} }
struct perf_evsel *
perf_evlist__find_evsel_by_str(struct perf_evlist *evlist,
const char *str)
{
struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) {
if (!evsel->name)
continue;
if (strcmp(str, evsel->name) == 0)
return evsel;
}
return NULL;
}
...@@ -294,4 +294,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, ...@@ -294,4 +294,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
struct perf_evsel *tracking_evsel); struct perf_evsel *tracking_evsel);
void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr);
struct perf_evsel *
perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str);
#endif /* __PERF_EVLIST_H */ #endif /* __PERF_EVLIST_H */
...@@ -225,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) ...@@ -225,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
if (evsel != NULL) if (evsel != NULL)
perf_evsel__init(evsel, attr, idx); perf_evsel__init(evsel, attr, idx);
if (perf_evsel__is_bpf_output(evsel)) {
evsel->attr.sample_type |= PERF_SAMPLE_RAW;
evsel->attr.sample_period = 1;
}
return evsel; return evsel;
} }
......
...@@ -364,6 +364,14 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel) ...@@ -364,6 +364,14 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
#undef FUNCTION_EVENT #undef FUNCTION_EVENT
} }
static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;
return (attr->config == PERF_COUNT_SW_BPF_OUTPUT) &&
(attr->type == PERF_TYPE_SOFTWARE);
}
struct perf_attr_details { struct perf_attr_details {
bool freq; bool freq;
bool verbose; bool verbose;
......
...@@ -179,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) ...@@ -179,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
if (h->transaction) if (h->transaction)
hists__new_col_len(hists, HISTC_TRANSACTION, hists__new_col_len(hists, HISTC_TRANSACTION,
hist_entry__transaction_len()); hist_entry__transaction_len());
if (h->trace_output)
hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
} }
void hists__output_recalc_col_len(struct hists *hists, int max_rows) void hists__output_recalc_col_len(struct hists *hists, int max_rows)
......
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "mem-events.h"
#include "debug.h"
#define E(t, n) { .tag = t, .name = n }
struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
E("ldlat-loads", "cpu/mem-loads,ldlat=30/P"),
E("ldlat-stores", "cpu/mem-stores/P"),
};
#undef E
int perf_mem_events__parse(const char *str)
{
char *tok, *saveptr = NULL;
bool found = false;
char *buf;
int j;
/* We need buffer that we know we can write to. */
buf = malloc(strlen(str) + 1);
if (!buf)
return -ENOMEM;
strcpy(buf, str);
tok = strtok_r((char *)buf, ",", &saveptr);
while (tok) {
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
struct perf_mem_event *e = &perf_mem_events[j];
if (strstr(e->tag, tok))
e->record = found = true;
}
tok = strtok_r(NULL, ",", &saveptr);
}
free(buf);
if (found)
return 0;
pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
return -1;
}
#ifndef __PERF_MEM_EVENTS_H
#define __PERF_MEM_EVENTS_H
#include <stdbool.h>
struct perf_mem_event {
bool record;
const char *tag;
const char *name;
};
enum {
PERF_MEM_EVENTS__LOAD,
PERF_MEM_EVENTS__STORE,
PERF_MEM_EVENTS__MAX,
};
extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
int perf_mem_events__parse(const char *str);
#endif /* __PERF_MEM_EVENTS_H */
...@@ -363,7 +363,7 @@ static int config_attr(struct perf_event_attr *attr, ...@@ -363,7 +363,7 @@ static int config_attr(struct perf_event_attr *attr,
int parse_events_add_cache(struct list_head *list, int *idx, int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2, char *type, char *op_result1, char *op_result2,
struct parse_events_error *error, struct parse_events_error *err,
struct list_head *head_config) struct list_head *head_config)
{ {
struct perf_event_attr attr; struct perf_event_attr attr;
...@@ -425,7 +425,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, ...@@ -425,7 +425,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
attr.type = PERF_TYPE_HW_CACHE; attr.type = PERF_TYPE_HW_CACHE;
if (head_config) { if (head_config) {
if (config_attr(&attr, head_config, error, if (config_attr(&attr, head_config, err,
config_term_common)) config_term_common))
return -EINVAL; return -EINVAL;
...@@ -581,6 +581,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, ...@@ -581,6 +581,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
struct __add_bpf_event_param { struct __add_bpf_event_param {
struct parse_events_evlist *data; struct parse_events_evlist *data;
struct list_head *list; struct list_head *list;
struct list_head *head_config;
}; };
static int add_bpf_event(struct probe_trace_event *tev, int fd, static int add_bpf_event(struct probe_trace_event *tev, int fd,
...@@ -597,7 +598,8 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, ...@@ -597,7 +598,8 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
tev->group, tev->event, fd); tev->group, tev->event, fd);
err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group,
tev->event, evlist->error, NULL); tev->event, evlist->error,
param->head_config);
if (err) { if (err) {
struct perf_evsel *evsel, *tmp; struct perf_evsel *evsel, *tmp;
...@@ -622,11 +624,12 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, ...@@ -622,11 +624,12 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
int parse_events_load_bpf_obj(struct parse_events_evlist *data, int parse_events_load_bpf_obj(struct parse_events_evlist *data,
struct list_head *list, struct list_head *list,
struct bpf_object *obj) struct bpf_object *obj,
struct list_head *head_config)
{ {
int err; int err;
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
struct __add_bpf_event_param param = {data, list}; struct __add_bpf_event_param param = {data, list, head_config};
static bool registered_unprobe_atexit = false; static bool registered_unprobe_atexit = false;
if (IS_ERR(obj) || !obj) { if (IS_ERR(obj) || !obj) {
...@@ -672,17 +675,99 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, ...@@ -672,17 +675,99 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
return err; return err;
} }
static int
parse_events_config_bpf(struct parse_events_evlist *data,
struct bpf_object *obj,
struct list_head *head_config)
{
struct parse_events_term *term;
int error_pos;
if (!head_config || list_empty(head_config))
return 0;
list_for_each_entry(term, head_config, list) {
char errbuf[BUFSIZ];
int err;
if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) {
snprintf(errbuf, sizeof(errbuf),
"Invalid config term for BPF object");
errbuf[BUFSIZ - 1] = '\0';
data->error->idx = term->err_term;
data->error->str = strdup(errbuf);
return -EINVAL;
}
err = bpf__config_obj(obj, term, data->evlist, &error_pos);
if (err) {
bpf__strerror_config_obj(obj, term, data->evlist,
&error_pos, err, errbuf,
sizeof(errbuf));
data->error->help = strdup(
"Hint:\tValid config terms:\n"
" \tmap:[<arraymap>].value<indices>=[value]\n"
" \tmap:[<eventmap>].event<indices>=[event]\n"
"\n"
" \twhere <indices> is something like [0,3...5] or [all]\n"
" \t(add -v to see detail)");
data->error->str = strdup(errbuf);
if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE)
data->error->idx = term->err_val;
else
data->error->idx = term->err_term + error_pos;
return err;
}
}
return 0;
}
/*
* Split config terms:
* perf record -e bpf.c/call-graph=fp,map:array.value[0]=1/ ...
* 'call-graph=fp' is 'evt config', should be applied to each
* events in bpf.c.
* 'map:array.value[0]=1' is 'obj config', should be processed
* with parse_events_config_bpf.
*
* Move object config terms from the first list to obj_head_config.
*/
static void
split_bpf_config_terms(struct list_head *evt_head_config,
struct list_head *obj_head_config)
{
struct parse_events_term *term, *temp;
/*
* Currectly, all possible user config term
* belong to bpf object. parse_events__is_hardcoded_term()
* happends to be a good flag.
*
* See parse_events_config_bpf() and
* config_term_tracepoint().
*/
list_for_each_entry_safe(term, temp, evt_head_config, list)
if (!parse_events__is_hardcoded_term(term))
list_move_tail(&term->list, obj_head_config);
}
int parse_events_load_bpf(struct parse_events_evlist *data, int parse_events_load_bpf(struct parse_events_evlist *data,
struct list_head *list, struct list_head *list,
char *bpf_file_name, char *bpf_file_name,
bool source) bool source,
struct list_head *head_config)
{ {
int err;
struct bpf_object *obj; struct bpf_object *obj;
LIST_HEAD(obj_head_config);
if (head_config)
split_bpf_config_terms(head_config, &obj_head_config);
obj = bpf__prepare_load(bpf_file_name, source); obj = bpf__prepare_load(bpf_file_name, source);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
int err;
err = PTR_ERR(obj); err = PTR_ERR(obj);
...@@ -700,7 +785,18 @@ int parse_events_load_bpf(struct parse_events_evlist *data, ...@@ -700,7 +785,18 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
return err; return err;
} }
return parse_events_load_bpf_obj(data, list, obj); err = parse_events_load_bpf_obj(data, list, obj, head_config);
if (err)
return err;
err = parse_events_config_bpf(data, obj, &obj_head_config);
/*
* Caller doesn't know anything about obj_head_config,
* so combine them together again before returnning.
*/
if (head_config)
list_splice_tail(&obj_head_config, head_config);
return err;
} }
static int static int
...@@ -841,10 +937,6 @@ void parse_events__shrink_config_terms(void) ...@@ -841,10 +937,6 @@ void parse_events__shrink_config_terms(void)
config_term_shrinked = true; config_term_shrinked = true;
} }
typedef int config_term_func_t(struct perf_event_attr *attr,
struct parse_events_term *term,
struct parse_events_error *err);
static int config_term_common(struct perf_event_attr *attr, static int config_term_common(struct perf_event_attr *attr,
struct parse_events_term *term, struct parse_events_term *term,
struct parse_events_error *err) struct parse_events_error *err)
...@@ -1488,6 +1580,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, ...@@ -1488,6 +1580,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
.list = LIST_HEAD_INIT(data.list), .list = LIST_HEAD_INIT(data.list),
.idx = evlist->nr_entries, .idx = evlist->nr_entries,
.error = err, .error = err,
.evlist = evlist,
}; };
int ret; int ret;
...@@ -2163,6 +2256,8 @@ void parse_events_terms__purge(struct list_head *terms) ...@@ -2163,6 +2256,8 @@ void parse_events_terms__purge(struct list_head *terms)
struct parse_events_term *term, *h; struct parse_events_term *term, *h;
list_for_each_entry_safe(term, h, terms, list) { list_for_each_entry_safe(term, h, terms, list) {
if (term->array.nr_ranges)
free(term->array.ranges);
list_del_init(&term->list); list_del_init(&term->list);
free(term); free(term);
} }
...@@ -2176,6 +2271,11 @@ void parse_events_terms__delete(struct list_head *terms) ...@@ -2176,6 +2271,11 @@ void parse_events_terms__delete(struct list_head *terms)
free(terms); free(terms);
} }
void parse_events__clear_array(struct parse_events_array *a)
{
free(a->ranges);
}
void parse_events_evlist_error(struct parse_events_evlist *data, void parse_events_evlist_error(struct parse_events_evlist *data,
int idx, const char *str) int idx, const char *str)
{ {
......
...@@ -72,8 +72,17 @@ enum { ...@@ -72,8 +72,17 @@ enum {
__PARSE_EVENTS__TERM_TYPE_NR, __PARSE_EVENTS__TERM_TYPE_NR,
}; };
struct parse_events_array {
size_t nr_ranges;
struct {
unsigned int start;
size_t length;
} *ranges;
};
struct parse_events_term { struct parse_events_term {
char *config; char *config;
struct parse_events_array array;
union { union {
char *str; char *str;
u64 num; u64 num;
...@@ -99,6 +108,7 @@ struct parse_events_evlist { ...@@ -99,6 +108,7 @@ struct parse_events_evlist {
int idx; int idx;
int nr_groups; int nr_groups;
struct parse_events_error *error; struct parse_events_error *error;
struct perf_evlist *evlist;
}; };
struct parse_events_terms { struct parse_events_terms {
...@@ -119,6 +129,7 @@ int parse_events_term__clone(struct parse_events_term **new, ...@@ -119,6 +129,7 @@ int parse_events_term__clone(struct parse_events_term **new,
struct parse_events_term *term); struct parse_events_term *term);
void parse_events_terms__delete(struct list_head *terms); void parse_events_terms__delete(struct list_head *terms);
void parse_events_terms__purge(struct list_head *terms); void parse_events_terms__purge(struct list_head *terms);
void parse_events__clear_array(struct parse_events_array *a);
int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_event(struct list_head *list, char *str, bool add);
int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events__modifier_group(struct list_head *list, char *event_mod);
int parse_events_name(struct list_head *list, char *name); int parse_events_name(struct list_head *list, char *name);
...@@ -129,12 +140,14 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, ...@@ -129,12 +140,14 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
int parse_events_load_bpf(struct parse_events_evlist *data, int parse_events_load_bpf(struct parse_events_evlist *data,
struct list_head *list, struct list_head *list,
char *bpf_file_name, char *bpf_file_name,
bool source); bool source,
struct list_head *head_config);
/* Provide this function for perf test */ /* Provide this function for perf test */
struct bpf_object; struct bpf_object;
int parse_events_load_bpf_obj(struct parse_events_evlist *data, int parse_events_load_bpf_obj(struct parse_events_evlist *data,
struct list_head *list, struct list_head *list,
struct bpf_object *obj); struct bpf_object *obj,
struct list_head *head_config);
int parse_events_add_numeric(struct parse_events_evlist *data, int parse_events_add_numeric(struct parse_events_evlist *data,
struct list_head *list, struct list_head *list,
u32 type, u64 config, u32 type, u64 config,
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
%{ %{
#include <errno.h> #include <errno.h>
#include "../perf.h" #include "../perf.h"
#include "parse-events-bison.h"
#include "parse-events.h" #include "parse-events.h"
#include "parse-events-bison.h"
char *parse_events_get_text(yyscan_t yyscanner); char *parse_events_get_text(yyscan_t yyscanner);
YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
...@@ -111,6 +111,7 @@ do { \ ...@@ -111,6 +111,7 @@ do { \
%x mem %x mem
%s config %s config
%x event %x event
%x array
group [^,{}/]*[{][^}]*[}][^,{}/]* group [^,{}/]*[{][^}]*[}][^,{}/]*
event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
...@@ -122,7 +123,7 @@ num_dec [0-9]+ ...@@ -122,7 +123,7 @@ num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+ num_hex 0x[a-fA-F0-9]+
num_raw_hex [a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+
name [a-zA-Z_*?][a-zA-Z0-9_*?.]* name [a-zA-Z_*?][a-zA-Z0-9_*?.]*
name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]* name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
/* If you add a modifier you need to update check_modifier() */ /* If you add a modifier you need to update check_modifier() */
modifier_event [ukhpPGHSDI]+ modifier_event [ukhpPGHSDI]+
modifier_bp [rwx]{1,3} modifier_bp [rwx]{1,3}
...@@ -176,6 +177,14 @@ modifier_bp [rwx]{1,3} ...@@ -176,6 +177,14 @@ modifier_bp [rwx]{1,3}
} }
<array>{
"]" { BEGIN(config); return ']'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
, { return ','; }
"\.\.\." { return PE_ARRAY_RANGE; }
}
<config>{ <config>{
/* /*
* Please update config_term_names when new static term is added. * Please update config_term_names when new static term is added.
...@@ -195,6 +204,8 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } ...@@ -195,6 +204,8 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
, { return ','; } , { return ','; }
"/" { BEGIN(INITIAL); return '/'; } "/" { BEGIN(INITIAL); return '/'; }
{name_minus} { return str(yyscanner, PE_NAME); } {name_minus} { return str(yyscanner, PE_NAME); }
\[all\] { return PE_ARRAY_ALL; }
"[" { BEGIN(array); return '['; }
} }
<mem>{ <mem>{
...@@ -237,6 +248,7 @@ cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU ...@@ -237,6 +248,7 @@ cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU
alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
/* /*
* We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately.
......
...@@ -48,6 +48,7 @@ static inc_group_count(struct list_head *list, ...@@ -48,6 +48,7 @@ static inc_group_count(struct list_head *list,
%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
%token PE_ERROR %token PE_ERROR
%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT %token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
%token PE_ARRAY_ALL PE_ARRAY_RANGE
%type <num> PE_VALUE %type <num> PE_VALUE
%type <num> PE_VALUE_SYM_HW %type <num> PE_VALUE_SYM_HW
%type <num> PE_VALUE_SYM_SW %type <num> PE_VALUE_SYM_SW
...@@ -83,6 +84,9 @@ static inc_group_count(struct list_head *list, ...@@ -83,6 +84,9 @@ static inc_group_count(struct list_head *list,
%type <head> group_def %type <head> group_def
%type <head> group %type <head> group
%type <head> groups %type <head> groups
%type <array> array
%type <array> array_term
%type <array> array_terms
%union %union
{ {
...@@ -94,6 +98,7 @@ static inc_group_count(struct list_head *list, ...@@ -94,6 +98,7 @@ static inc_group_count(struct list_head *list,
char *sys; char *sys;
char *event; char *event;
} tracepoint_name; } tracepoint_name;
struct parse_events_array array;
} }
%% %%
...@@ -437,24 +442,26 @@ PE_RAW opt_event_config ...@@ -437,24 +442,26 @@ PE_RAW opt_event_config
} }
event_bpf_file: event_bpf_file:
PE_BPF_OBJECT PE_BPF_OBJECT opt_event_config
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct parse_events_error *error = data->error; struct parse_events_error *error = data->error;
struct list_head *list; struct list_head *list;
ALLOC_LIST(list); ALLOC_LIST(list);
ABORT_ON(parse_events_load_bpf(data, list, $1, false)); ABORT_ON(parse_events_load_bpf(data, list, $1, false, $2));
parse_events_terms__delete($2);
$$ = list; $$ = list;
} }
| |
PE_BPF_SOURCE PE_BPF_SOURCE opt_event_config
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list; struct list_head *list;
ALLOC_LIST(list); ALLOC_LIST(list);
ABORT_ON(parse_events_load_bpf(data, list, $1, true)); ABORT_ON(parse_events_load_bpf(data, list, $1, true, $2));
parse_events_terms__delete($2);
$$ = list; $$ = list;
} }
...@@ -570,6 +577,86 @@ PE_TERM ...@@ -570,6 +577,86 @@ PE_TERM
ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL)); ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL));
$$ = term; $$ = term;
} }
|
PE_NAME array '=' PE_NAME
{
struct parse_events_term *term;
int i;
ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
$1, $4, &@1, &@4));
term->array = $2;
$$ = term;
}
|
PE_NAME array '=' PE_VALUE
{
struct parse_events_term *term;
ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
$1, $4, &@1, &@4));
term->array = $2;
$$ = term;
}
array:
'[' array_terms ']'
{
$$ = $2;
}
|
PE_ARRAY_ALL
{
$$.nr_ranges = 0;
$$.ranges = NULL;
}
array_terms:
array_terms ',' array_term
{
struct parse_events_array new_array;
new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges;
new_array.ranges = malloc(sizeof(new_array.ranges[0]) *
new_array.nr_ranges);
ABORT_ON(!new_array.ranges);
memcpy(&new_array.ranges[0], $1.ranges,
$1.nr_ranges * sizeof(new_array.ranges[0]));
memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges,
$3.nr_ranges * sizeof(new_array.ranges[0]));
free($1.ranges);
free($3.ranges);
$$ = new_array;
}
|
array_term
array_term:
PE_VALUE
{
struct parse_events_array array;
array.nr_ranges = 1;
array.ranges = malloc(sizeof(array.ranges[0]));
ABORT_ON(!array.ranges);
array.ranges[0].start = $1;
array.ranges[0].length = 1;
$$ = array;
}
|
PE_VALUE PE_ARRAY_RANGE PE_VALUE
{
struct parse_events_array array;
ABORT_ON($3 < $1);
array.nr_ranges = 1;
array.ranges = malloc(sizeof(array.ranges[0]));
ABORT_ON(!array.ranges);
array.ranges[0].start = $1;
array.ranges[0].length = $3 - $1 + 1;
$$ = array;
}
sep_dc: ':' | sep_dc: ':' |
......
...@@ -284,13 +284,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) ...@@ -284,13 +284,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
{ {
struct dirent *evt_ent; struct dirent *evt_ent;
DIR *event_dir; DIR *event_dir;
int ret = 0;
event_dir = opendir(dir); event_dir = opendir(dir);
if (!event_dir) if (!event_dir)
return -EINVAL; return -EINVAL;
while (!ret && (evt_ent = readdir(event_dir))) { while ((evt_ent = readdir(event_dir))) {
char path[PATH_MAX]; char path[PATH_MAX];
char *name = evt_ent->d_name; char *name = evt_ent->d_name;
FILE *file; FILE *file;
...@@ -306,17 +305,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) ...@@ -306,17 +305,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
snprintf(path, PATH_MAX, "%s/%s", dir, name); snprintf(path, PATH_MAX, "%s/%s", dir, name);
ret = -EINVAL;
file = fopen(path, "r"); file = fopen(path, "r");
if (!file) if (!file) {
break; pr_debug("Cannot open %s\n", path);
continue;
}
ret = perf_pmu__new_alias(head, dir, name, file); if (perf_pmu__new_alias(head, dir, name, file) < 0)
pr_debug("Cannot set up %s\n", name);
fclose(file); fclose(file);
} }
closedir(event_dir); closedir(event_dir);
return ret; return 0;
} }
/* /*
......
...@@ -286,36 +286,35 @@ struct sort_entry sort_sym = { ...@@ -286,36 +286,35 @@ struct sort_entry sort_sym = {
/* --sort srcline */ /* --sort srcline */
static char *hist_entry__get_srcline(struct hist_entry *he)
{
struct map *map = he->ms.map;
if (!map)
return SRCLINE_UNKNOWN;
return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
he->ms.sym, true);
}
static int64_t static int64_t
sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
if (!left->srcline) { if (!left->srcline)
if (!left->ms.map) left->srcline = hist_entry__get_srcline(left);
left->srcline = SRCLINE_UNKNOWN; if (!right->srcline)
else { right->srcline = hist_entry__get_srcline(right);
struct map *map = left->ms.map;
left->srcline = get_srcline(map->dso,
map__rip_2objdump(map, left->ip),
left->ms.sym, true);
}
}
if (!right->srcline) {
if (!right->ms.map)
right->srcline = SRCLINE_UNKNOWN;
else {
struct map *map = right->ms.map;
right->srcline = get_srcline(map->dso,
map__rip_2objdump(map, right->ip),
right->ms.sym, true);
}
}
return strcmp(right->srcline, left->srcline); return strcmp(right->srcline, left->srcline);
} }
static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline); if (!he->srcline)
he->srcline = hist_entry__get_srcline(he);
return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
} }
struct sort_entry sort_srcline = { struct sort_entry sort_srcline = {
...@@ -329,11 +328,14 @@ struct sort_entry sort_srcline = { ...@@ -329,11 +328,14 @@ struct sort_entry sort_srcline = {
static char no_srcfile[1]; static char no_srcfile[1];
static char *get_srcfile(struct hist_entry *e) static char *hist_entry__get_srcfile(struct hist_entry *e)
{ {
char *sf, *p; char *sf, *p;
struct map *map = e->ms.map; struct map *map = e->ms.map;
if (!map)
return no_srcfile;
sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
e->ms.sym, false, true); e->ms.sym, false, true);
if (!strcmp(sf, SRCLINE_UNKNOWN)) if (!strcmp(sf, SRCLINE_UNKNOWN))
...@@ -350,25 +352,21 @@ static char *get_srcfile(struct hist_entry *e) ...@@ -350,25 +352,21 @@ static char *get_srcfile(struct hist_entry *e)
static int64_t static int64_t
sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
if (!left->srcfile) { if (!left->srcfile)
if (!left->ms.map) left->srcfile = hist_entry__get_srcfile(left);
left->srcfile = no_srcfile; if (!right->srcfile)
else right->srcfile = hist_entry__get_srcfile(right);
left->srcfile = get_srcfile(left);
}
if (!right->srcfile) {
if (!right->ms.map)
right->srcfile = no_srcfile;
else
right->srcfile = get_srcfile(right);
}
return strcmp(right->srcfile, left->srcfile); return strcmp(right->srcfile, left->srcfile);
} }
static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); if (!he->srcfile)
he->srcfile = hist_entry__get_srcfile(he);
return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
} }
struct sort_entry sort_srcfile = { struct sort_entry sort_srcfile = {
...@@ -485,9 +483,6 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -485,9 +483,6 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
if (right->trace_output == NULL) if (right->trace_output == NULL)
right->trace_output = get_trace_output(right); right->trace_output = get_trace_output(right);
hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
return strcmp(right->trace_output, left->trace_output); return strcmp(right->trace_output, left->trace_output);
} }
...@@ -498,11 +493,11 @@ static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, ...@@ -498,11 +493,11 @@ static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
evsel = hists_to_evsel(he->hists); evsel = hists_to_evsel(he->hists);
if (evsel->attr.type != PERF_TYPE_TRACEPOINT) if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
return scnprintf(bf, size, "%-*.*s", width, width, "N/A"); return scnprintf(bf, size, "%-.*s", width, "N/A");
if (he->trace_output == NULL) if (he->trace_output == NULL)
he->trace_output = get_trace_output(he); he->trace_output = get_trace_output(he);
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output); return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
} }
struct sort_entry sort_trace = { struct sort_entry sort_trace = {
...@@ -843,7 +838,6 @@ static const char * const tlb_access[] = { ...@@ -843,7 +838,6 @@ static const char * const tlb_access[] = {
"Walker", "Walker",
"Fault", "Fault",
}; };
#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
...@@ -865,7 +859,7 @@ static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, ...@@ -865,7 +859,7 @@ static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
/* already taken care of */ /* already taken care of */
m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
if (!(m & 0x1)) if (!(m & 0x1))
continue; continue;
if (l) { if (l) {
...@@ -920,7 +914,6 @@ static const char * const mem_lvl[] = { ...@@ -920,7 +914,6 @@ static const char * const mem_lvl[] = {
"I/O", "I/O",
"Uncached", "Uncached",
}; };
#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
...@@ -942,7 +935,7 @@ static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, ...@@ -942,7 +935,7 @@ static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
/* already taken care of */ /* already taken care of */
m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
if (!(m & 0x1)) if (!(m & 0x1))
continue; continue;
if (l) { if (l) {
...@@ -988,7 +981,6 @@ static const char * const snoop_access[] = { ...@@ -988,7 +981,6 @@ static const char * const snoop_access[] = {
"Hit", "Hit",
"HitM", "HitM",
}; };
#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
...@@ -1003,7 +995,7 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, ...@@ -1003,7 +995,7 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
if (he->mem_info) if (he->mem_info)
m = he->mem_info->data_src.mem_snoop; m = he->mem_info->data_src.mem_snoop;
for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
if (!(m & 0x1)) if (!(m & 0x1))
continue; continue;
if (l) { if (l) {
...@@ -1020,12 +1012,6 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, ...@@ -1020,12 +1012,6 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
return repsep_snprintf(bf, size, "%-*s", width, out); return repsep_snprintf(bf, size, "%-*s", width, out);
} }
static inline u64 cl_address(u64 address)
{
/* return the cacheline of the address */
return (address & ~(cacheline_size - 1));
}
static int64_t static int64_t
sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
...@@ -1835,6 +1821,20 @@ bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt) ...@@ -1835,6 +1821,20 @@ bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
return fmt->cmp == __sort__hde_cmp; return fmt->cmp == __sort__hde_cmp;
} }
static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
{
struct hpp_dynamic_entry *hde_a;
struct hpp_dynamic_entry *hde_b;
if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
return false;
hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
return hde_a->field == hde_b->field;
}
static void hde_free(struct perf_hpp_fmt *fmt) static void hde_free(struct perf_hpp_fmt *fmt)
{ {
struct hpp_dynamic_entry *hde; struct hpp_dynamic_entry *hde;
...@@ -1867,6 +1867,7 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field) ...@@ -1867,6 +1867,7 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
hde->hpp.cmp = __sort__hde_cmp; hde->hpp.cmp = __sort__hde_cmp;
hde->hpp.collapse = __sort__hde_cmp; hde->hpp.collapse = __sort__hde_cmp;
hde->hpp.sort = __sort__hde_cmp; hde->hpp.sort = __sort__hde_cmp;
hde->hpp.equal = __sort__hde_equal;
hde->hpp.free = hde_free; hde->hpp.free = hde_free;
INIT_LIST_HEAD(&hde->hpp.list); INIT_LIST_HEAD(&hde->hpp.list);
......
...@@ -162,6 +162,17 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he) ...@@ -162,6 +162,17 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he)
return period * 100.0 / total_period; return period * 100.0 / total_period;
} }
static inline u64 cl_address(u64 address)
{
/* return the cacheline of the address */
return (address & ~(cacheline_size - 1));
}
static inline u64 cl_offset(u64 address)
{
/* return the cacheline of the address */
return (address & (cacheline_size - 1));
}
enum sort_mode { enum sort_mode {
SORT_MODE__NORMAL, SORT_MODE__NORMAL,
......
...@@ -51,30 +51,6 @@ void strbuf_grow(struct strbuf *sb, size_t extra) ...@@ -51,30 +51,6 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
} }
static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
const void *data, size_t dlen)
{
if (pos + len < pos)
die("you want to use way too much memory");
if (pos > sb->len)
die("`pos' is too far after the end of the buffer");
if (pos + len > sb->len)
die("`pos + len' is too far after the end of the buffer");
if (dlen >= len)
strbuf_grow(sb, dlen - len);
memmove(sb->buf + pos + dlen,
sb->buf + pos + len,
sb->len - pos - len);
memcpy(sb->buf + pos, data, dlen);
strbuf_setlen(sb, sb->len + dlen - len);
}
void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
{
strbuf_splice(sb, pos, len, NULL, 0);
}
void strbuf_add(struct strbuf *sb, const void *data, size_t len) void strbuf_add(struct strbuf *sb, const void *data, size_t len)
{ {
strbuf_grow(sb, len); strbuf_grow(sb, len);
......
...@@ -77,8 +77,6 @@ static inline void strbuf_addch(struct strbuf *sb, int c) { ...@@ -77,8 +77,6 @@ static inline void strbuf_addch(struct strbuf *sb, int c) {
sb->buf[sb->len] = '\0'; sb->buf[sb->len] = '\0';
} }
extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
extern void strbuf_add(struct strbuf *, const void *, size_t); extern void strbuf_add(struct strbuf *, const void *, size_t);
static inline void strbuf_addstr(struct strbuf *sb, const char *s) { static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
strbuf_add(sb, s, strlen(s)); strbuf_add(sb, s, strlen(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