mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 00:52:01 +00:00
142544a938
Add a new 'evlist' control command to display all the evlist events. When it is received, perf will scan and print current evlist into perf record terminal. The interface string for control file is: evlist [-v|-g|-F] The syntax follows perf evlist command: -F Show just the sample frequency used for each event. -v Show all fields. -g Show event group information. Example session: terminal 1: # mkfifo control ack # perf record --control=fifo:control,ack -e '{cycles,instructions}' terminal 2: # echo evlist > control terminal 1: cycles instructions dummy:HG terminal 2: # echo 'evlist -v' > control terminal 1: cycles: size: 120, { sample_period, sample_freq }: 4000, sample_type: \ IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, freq: 1, \ sample_id_all: 1, exclude_guest: 1 instructions: size: 120, config: 0x1, { sample_period, sample_freq }: 4000, \ sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, inherit: 1, freq: 1, \ sample_id_all: 1, exclude_guest: 1 dummy:HG: type: 1, size: 120, config: 0x9, { sample_period, sample_freq }: 4000, \ sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, inherit: 1, mmap: 1, \ comm: 1, freq: 1, task: 1, sample_id_all: 1, mmap2: 1, comm_exec: 1, ksymbol: 1, \ bpf_event: 1 terminal 2: # echo 'evlist -g' > control terminal 1: {cycles,instructions} dummy:HG terminal 2: # echo 'evlist -F' > control terminal 1: cycles: sample_freq=4000 instructions: sample_freq=4000 dummy:HG: sample_freq=4000 This new evlist command is handy to get real event names when wildcards are used. Adding evsel_fprintf.c object to python/perf.so build, because it's now evlist.c dependency. Adding PYTHON_PERF define for python/perf.so compilation, so we can use it to compile in only evsel__fprintf from evsel_fprintf.c object. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Namhyung Kim <namhyung@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexei Budankov <abudankov@huawei.com> Cc: Ian Rogers <irogers@google.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lore.kernel.org/lkml/20201226232038.390883-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
244 lines
6.0 KiB
C
244 lines
6.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <traceevent/event-parse.h>
|
|
#include "evsel.h"
|
|
#include "util/evsel_fprintf.h"
|
|
#include "util/event.h"
|
|
#include "callchain.h"
|
|
#include "map.h"
|
|
#include "strlist.h"
|
|
#include "symbol.h"
|
|
#include "srcline.h"
|
|
|
|
static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int ret = 0;
|
|
|
|
if (!*first) {
|
|
ret += fprintf(fp, ",");
|
|
} else {
|
|
ret += fprintf(fp, ":");
|
|
*first = false;
|
|
}
|
|
|
|
va_start(args, fmt);
|
|
ret += vfprintf(fp, fmt, args);
|
|
va_end(args);
|
|
return ret;
|
|
}
|
|
|
|
static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv)
|
|
{
|
|
return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val);
|
|
}
|
|
|
|
int evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp)
|
|
{
|
|
bool first = true;
|
|
int printed = 0;
|
|
|
|
if (details->event_group) {
|
|
struct evsel *pos;
|
|
|
|
if (!evsel__is_group_leader(evsel))
|
|
return 0;
|
|
|
|
if (evsel->core.nr_members > 1)
|
|
printed += fprintf(fp, "%s{", evsel->group_name ?: "");
|
|
|
|
printed += fprintf(fp, "%s", evsel__name(evsel));
|
|
for_each_group_member(pos, evsel)
|
|
printed += fprintf(fp, ",%s", evsel__name(pos));
|
|
|
|
if (evsel->core.nr_members > 1)
|
|
printed += fprintf(fp, "}");
|
|
goto out;
|
|
}
|
|
|
|
printed += fprintf(fp, "%s", evsel__name(evsel));
|
|
|
|
if (details->verbose) {
|
|
printed += perf_event_attr__fprintf(fp, &evsel->core.attr,
|
|
__print_attr__fprintf, &first);
|
|
} else if (details->freq) {
|
|
const char *term = "sample_freq";
|
|
|
|
if (!evsel->core.attr.freq)
|
|
term = "sample_period";
|
|
|
|
printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
|
|
term, (u64)evsel->core.attr.sample_freq);
|
|
}
|
|
|
|
if (details->trace_fields) {
|
|
struct tep_format_field *field;
|
|
|
|
if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
|
|
printed += comma_fprintf(fp, &first, " (not a tracepoint)");
|
|
goto out;
|
|
}
|
|
|
|
field = evsel->tp_format->format.fields;
|
|
if (field == NULL) {
|
|
printed += comma_fprintf(fp, &first, " (no trace field)");
|
|
goto out;
|
|
}
|
|
|
|
printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
|
|
|
|
field = field->next;
|
|
while (field) {
|
|
printed += comma_fprintf(fp, &first, "%s", field->name);
|
|
field = field->next;
|
|
}
|
|
}
|
|
out:
|
|
fputc('\n', fp);
|
|
return ++printed;
|
|
}
|
|
|
|
#ifndef PYTHON_PERF
|
|
int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
|
|
unsigned int print_opts, struct callchain_cursor *cursor,
|
|
struct strlist *bt_stop_list, FILE *fp)
|
|
{
|
|
int printed = 0;
|
|
struct callchain_cursor_node *node;
|
|
int print_ip = print_opts & EVSEL__PRINT_IP;
|
|
int print_sym = print_opts & EVSEL__PRINT_SYM;
|
|
int print_dso = print_opts & EVSEL__PRINT_DSO;
|
|
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
|
|
int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
|
|
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
|
|
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
|
|
int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW;
|
|
int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED;
|
|
char s = print_oneline ? ' ' : '\t';
|
|
bool first = true;
|
|
|
|
if (sample->callchain) {
|
|
struct addr_location node_al;
|
|
|
|
callchain_cursor_commit(cursor);
|
|
|
|
while (1) {
|
|
struct symbol *sym;
|
|
struct map *map;
|
|
u64 addr = 0;
|
|
|
|
node = callchain_cursor_current(cursor);
|
|
if (!node)
|
|
break;
|
|
|
|
sym = node->ms.sym;
|
|
map = node->ms.map;
|
|
|
|
if (sym && sym->ignore && print_skip_ignored)
|
|
goto next;
|
|
|
|
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
|
|
|
|
if (print_arrow && !first)
|
|
printed += fprintf(fp, " <-");
|
|
|
|
if (print_ip)
|
|
printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
|
|
|
|
if (map)
|
|
addr = map->map_ip(map, node->ip);
|
|
|
|
if (print_sym) {
|
|
printed += fprintf(fp, " ");
|
|
node_al.addr = addr;
|
|
node_al.map = map;
|
|
|
|
if (print_symoffset) {
|
|
printed += __symbol__fprintf_symname_offs(sym, &node_al,
|
|
print_unknown_as_addr,
|
|
true, fp);
|
|
} else {
|
|
printed += __symbol__fprintf_symname(sym, &node_al,
|
|
print_unknown_as_addr, fp);
|
|
}
|
|
}
|
|
|
|
if (print_dso && (!sym || !sym->inlined)) {
|
|
printed += fprintf(fp, " (");
|
|
printed += map__fprintf_dsoname(map, fp);
|
|
printed += fprintf(fp, ")");
|
|
}
|
|
|
|
if (print_srcline)
|
|
printed += map__fprintf_srcline(map, addr, "\n ", fp);
|
|
|
|
if (sym && sym->inlined)
|
|
printed += fprintf(fp, " (inlined)");
|
|
|
|
if (!print_oneline)
|
|
printed += fprintf(fp, "\n");
|
|
|
|
/* Add srccode here too? */
|
|
if (bt_stop_list && sym &&
|
|
strlist__has_entry(bt_stop_list, sym->name)) {
|
|
break;
|
|
}
|
|
|
|
first = false;
|
|
next:
|
|
callchain_cursor_advance(cursor);
|
|
}
|
|
}
|
|
|
|
return printed;
|
|
}
|
|
|
|
int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
|
|
int left_alignment, unsigned int print_opts,
|
|
struct callchain_cursor *cursor, struct strlist *bt_stop_list, FILE *fp)
|
|
{
|
|
int printed = 0;
|
|
int print_ip = print_opts & EVSEL__PRINT_IP;
|
|
int print_sym = print_opts & EVSEL__PRINT_SYM;
|
|
int print_dso = print_opts & EVSEL__PRINT_DSO;
|
|
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
|
|
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
|
|
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
|
|
|
|
if (cursor != NULL) {
|
|
printed += sample__fprintf_callchain(sample, left_alignment, print_opts,
|
|
cursor, bt_stop_list, fp);
|
|
} else {
|
|
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
|
|
|
|
if (print_ip)
|
|
printed += fprintf(fp, "%16" PRIx64, sample->ip);
|
|
|
|
if (print_sym) {
|
|
printed += fprintf(fp, " ");
|
|
if (print_symoffset) {
|
|
printed += __symbol__fprintf_symname_offs(al->sym, al,
|
|
print_unknown_as_addr,
|
|
true, fp);
|
|
} else {
|
|
printed += __symbol__fprintf_symname(al->sym, al,
|
|
print_unknown_as_addr, fp);
|
|
}
|
|
}
|
|
|
|
if (print_dso) {
|
|
printed += fprintf(fp, " (");
|
|
printed += map__fprintf_dsoname(al->map, fp);
|
|
printed += fprintf(fp, ")");
|
|
}
|
|
|
|
if (print_srcline)
|
|
printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
|
|
}
|
|
|
|
return printed;
|
|
}
|
|
#endif /* PYTHON_PERF */
|