perf/core improvements and fixes:
New features: - Generate comm, fork and exit events when converting perf.data files to CTF (Wang Nan) Infrastructure: - Add libbabeltrace to build-test (Wang Nan) - 'perf record' prep work to support multiple evlists (Wang Nan) - Remove unused hist_entry__annotate function (Ravi Bangoria) - Add more toolchain triplets (Ravi Bangoria) - Update message for slang devel packages on Ubuntu (Neeraj Badlani) - Generalize handling of 'ret' instructions in the annotate TUI (Naveen N. Rao) - Use proper dso name for is_regular_file, fixing device file handling (Jiri Olsa) Build Fixes: - Add missing config.h include, fixing the build with libbabeltrace (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJXcoITAAoJENZQFvNTUqpAWxwP/j/h0hGej0/OtzmYIvkeMNXL Ei/G1SPjaVS1HxE2UeqcSVFN9dYXHXNwC/9D9Zhg3nTVeVqdTTtk4l2AQcBt7/0b 5dHFD3mue5iSPFR2nh6nkidb2AyplrCd192Ovww0S/hy26HkNF/8X02aknpOm4SL u+S6oYo1gaKCMh7FXYqxFa4uMfzrnCQH5YmEUyuuj3S7fDyidVYVsHfa7DAvzZF9 gyFnqHRX9H+FpWXkJtaTAaDEQtMvKqvvjLglWDm4W5z0dvyIvVpTiJwm3AtPJ17a 7rfg+D8V/pA5rcC5HsUwzTrrwzNH0/fDwZgrn50/FImaVyR8MbowgUG+xRGctqsk ITmW0FQisJngBekZ7aMl8/WgZ5XfvfwtPo9sfvyTnryqbG1ZizWmnOCFg9PpfSWK 08kNQac/t4Uo6qZmL1x3lw8T60EGsOJaVwllNKPcF5CO0ff5cXKnXTkEyCoCcS20 RJ8mFJeqol76gmjAy5rYdK9hLMDTUlrHIB2gTE9s1woaiuAvhpnXl0QVx6q38e3L H0f1JFF0Ny5Nb5W+xOUFXiNmVAOKoFL9hS4GOpzDyTozVBTRazjMQf5srfskrhlb 4dpvwJqIFHo/NaKXZcHYcT7wYFaE6gbApjw5bUaFPMvhYOJ/DefW8FSk8btcma1N LZ65UEGakqS5gbFX9NdU =rSZA -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-20160628' 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: - Generate comm, fork and exit events when converting perf.data files to CTF (Wang Nan) Infrastructure changes: - Add libbabeltrace to build-test (Wang Nan) - 'perf record' prep work to support multiple evlists (Wang Nan) - Remove unused hist_entry__annotate function (Ravi Bangoria) - Add more toolchain triplets (Ravi Bangoria) - Update message for slang devel packages on Ubuntu (Neeraj Badlani) - Generalize handling of 'ret' instructions in the annotate TUI (Naveen N. Rao) - Use proper dso name for is_regular_file, fixing device file handling (Jiri Olsa) Build Fixes: - Add missing config.h include, fixing the build with libbabeltrace (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
d905768c9e
|
@ -34,6 +34,10 @@ OPTIONS for 'convert'
|
|||
--verbose::
|
||||
Be more verbose (show counter open errors, etc).
|
||||
|
||||
--all::
|
||||
Convert all events, including non-sample events (comm, fork, ...), to output.
|
||||
Default is off, only convert samples.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf[1]
|
||||
|
|
|
@ -9,34 +9,44 @@ const char *const arm_triplets[] = {
|
|||
"arm-unknown-linux-",
|
||||
"arm-unknown-linux-gnu-",
|
||||
"arm-unknown-linux-gnueabi-",
|
||||
"arm-linux-gnu-",
|
||||
"arm-linux-gnueabihf-",
|
||||
"arm-none-eabi-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const arm64_triplets[] = {
|
||||
"aarch64-linux-android-",
|
||||
"aarch64-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const powerpc_triplets[] = {
|
||||
"powerpc-unknown-linux-gnu-",
|
||||
"powerpc64-unknown-linux-gnu-",
|
||||
"powerpc64-linux-gnu-",
|
||||
"powerpc64le-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const s390_triplets[] = {
|
||||
"s390-ibm-linux-",
|
||||
"s390x-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const sh_triplets[] = {
|
||||
"sh-unknown-linux-gnu-",
|
||||
"sh64-unknown-linux-gnu-",
|
||||
"sh-linux-gnu-",
|
||||
"sh64-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const sparc_triplets[] = {
|
||||
"sparc-unknown-linux-gnu-",
|
||||
"sparc64-unknown-linux-gnu-",
|
||||
"sparc64-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -49,12 +59,19 @@ const char *const x86_triplets[] = {
|
|||
"i386-pc-linux-gnu-",
|
||||
"i686-linux-android-",
|
||||
"i686-android-linux-",
|
||||
"x86_64-linux-gnu-",
|
||||
"i586-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *const mips_triplets[] = {
|
||||
"mips-unknown-linux-gnu-",
|
||||
"mipsel-linux-android-",
|
||||
"mips-linux-gnu-",
|
||||
"mips64-linux-gnu-",
|
||||
"mips64el-linux-gnuabi64-",
|
||||
"mips64-linux-gnuabi64-",
|
||||
"mipsel-linux-gnu-",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "perf.h"
|
||||
#include "debug.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "data-convert.h"
|
||||
#include "data-convert-bt.h"
|
||||
|
||||
typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
|
||||
|
@ -53,14 +54,18 @@ static int cmd_data_convert(int argc, const char **argv,
|
|||
const char *prefix __maybe_unused)
|
||||
{
|
||||
const char *to_ctf = NULL;
|
||||
bool force = false;
|
||||
struct perf_data_convert_opts opts = {
|
||||
.force = false,
|
||||
.all = false,
|
||||
};
|
||||
const struct option options[] = {
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
#ifdef HAVE_LIBBABELTRACE_SUPPORT
|
||||
OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"),
|
||||
#endif
|
||||
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
||||
OPT_BOOLEAN('f', "force", &opts.force, "don't complain, do it"),
|
||||
OPT_BOOLEAN(0, "all", &opts.all, "Convert all events"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -78,7 +83,7 @@ static int cmd_data_convert(int argc, const char **argv,
|
|||
|
||||
if (to_ctf) {
|
||||
#ifdef HAVE_LIBBABELTRACE_SUPPORT
|
||||
return bt_convert__perf2ctf(input_name, to_ctf, force);
|
||||
return bt_convert__perf2ctf(input_name, to_ctf, &opts);
|
||||
#else
|
||||
pr_err("The libbabeltrace support is not compiled in.\n");
|
||||
return -1;
|
||||
|
|
|
@ -132,9 +132,9 @@ rb_find_range(struct perf_evlist *evlist,
|
|||
return backward_rb_find_range(data, mask, head, start, end);
|
||||
}
|
||||
|
||||
static int record__mmap_read(struct record *rec, int idx)
|
||||
static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int idx)
|
||||
{
|
||||
struct perf_mmap *md = &rec->evlist->mmap[idx];
|
||||
struct perf_mmap *md = &evlist->mmap[idx];
|
||||
u64 head = perf_mmap__read_head(md);
|
||||
u64 old = md->prev;
|
||||
u64 end = head, start = old;
|
||||
|
@ -143,7 +143,7 @@ static int record__mmap_read(struct record *rec, int idx)
|
|||
void *buf;
|
||||
int rc = 0;
|
||||
|
||||
if (rb_find_range(rec->evlist, data, md->mask, head,
|
||||
if (rb_find_range(evlist, data, md->mask, head,
|
||||
old, &start, &end))
|
||||
return -1;
|
||||
|
||||
|
@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, int idx)
|
|||
WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
|
||||
|
||||
md->prev = head;
|
||||
perf_evlist__mmap_consume(rec->evlist, idx);
|
||||
perf_evlist__mmap_consume(evlist, idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, int idx)
|
|||
}
|
||||
|
||||
md->prev = head;
|
||||
perf_evlist__mmap_consume(rec->evlist, idx);
|
||||
perf_evlist__mmap_consume(evlist, idx);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
@ -342,6 +342,40 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
|
|||
|
||||
#endif
|
||||
|
||||
static int record__mmap_evlist(struct record *rec,
|
||||
struct perf_evlist *evlist)
|
||||
{
|
||||
struct record_opts *opts = &rec->opts;
|
||||
char msg[512];
|
||||
|
||||
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
|
||||
opts->auxtrace_mmap_pages,
|
||||
opts->auxtrace_snapshot_mode) < 0) {
|
||||
if (errno == EPERM) {
|
||||
pr_err("Permission error mapping pages.\n"
|
||||
"Consider increasing "
|
||||
"/proc/sys/kernel/perf_event_mlock_kb,\n"
|
||||
"or try again with a smaller value of -m/--mmap_pages.\n"
|
||||
"(current value: %u,%u)\n",
|
||||
opts->mmap_pages, opts->auxtrace_mmap_pages);
|
||||
return -errno;
|
||||
} else {
|
||||
pr_err("failed to mmap with %d (%s)\n", errno,
|
||||
strerror_r(errno, msg, sizeof(msg)));
|
||||
if (errno)
|
||||
return -errno;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int record__mmap(struct record *rec)
|
||||
{
|
||||
return record__mmap_evlist(rec, rec->evlist);
|
||||
}
|
||||
|
||||
static int record__open(struct record *rec)
|
||||
{
|
||||
char msg[512];
|
||||
|
@ -378,27 +412,9 @@ static int record__open(struct record *rec)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
|
||||
opts->auxtrace_mmap_pages,
|
||||
opts->auxtrace_snapshot_mode) < 0) {
|
||||
if (errno == EPERM) {
|
||||
pr_err("Permission error mapping pages.\n"
|
||||
"Consider increasing "
|
||||
"/proc/sys/kernel/perf_event_mlock_kb,\n"
|
||||
"or try again with a smaller value of -m/--mmap_pages.\n"
|
||||
"(current value: %u,%u)\n",
|
||||
opts->mmap_pages, opts->auxtrace_mmap_pages);
|
||||
rc = -errno;
|
||||
} else {
|
||||
pr_err("failed to mmap with %d (%s)\n", errno,
|
||||
strerror_r(errno, msg, sizeof(msg)));
|
||||
if (errno)
|
||||
rc = -errno;
|
||||
else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
rc = record__mmap(rec);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->evlist = evlist;
|
||||
perf_session__set_id_hdr_size(session);
|
||||
|
@ -482,17 +498,20 @@ static struct perf_event_header finished_round_event = {
|
|||
.type = PERF_RECORD_FINISHED_ROUND,
|
||||
};
|
||||
|
||||
static int record__mmap_read_all(struct record *rec)
|
||||
static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist)
|
||||
{
|
||||
u64 bytes_written = rec->bytes_written;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
for (i = 0; i < rec->evlist->nr_mmaps; i++) {
|
||||
struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
|
||||
if (!evlist)
|
||||
return 0;
|
||||
|
||||
if (rec->evlist->mmap[i].base) {
|
||||
if (record__mmap_read(rec, i) != 0) {
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap;
|
||||
|
||||
if (evlist->mmap[i].base) {
|
||||
if (record__mmap_read(rec, evlist, i) != 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
@ -516,6 +535,17 @@ static int record__mmap_read_all(struct record *rec)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int record__mmap_read_all(struct record *rec)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = record__mmap_read_evlist(rec, rec->evlist);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void record__init_features(struct record *rec)
|
||||
{
|
||||
struct perf_session *session = rec->session;
|
||||
|
@ -656,10 +686,21 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct perf_event_mmap_page *
|
||||
perf_evlist__pick_pc(struct perf_evlist *evlist)
|
||||
{
|
||||
if (evlist && evlist->mmap && evlist->mmap[0].base)
|
||||
return evlist->mmap[0].base;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct perf_event_mmap_page *record__pick_pc(struct record *rec)
|
||||
{
|
||||
if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base)
|
||||
return rec->evlist->mmap[0].base;
|
||||
const struct perf_event_mmap_page *pc;
|
||||
|
||||
pc = perf_evlist__pick_pc(rec->evlist);
|
||||
if (pc)
|
||||
return pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,7 +482,7 @@ endif
|
|||
|
||||
ifndef NO_SLANG
|
||||
ifneq ($(feature-libslang), 1)
|
||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
|
||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
|
||||
NO_SLANG := 1
|
||||
else
|
||||
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
||||
|
|
|
@ -81,6 +81,7 @@ make_no_libbionic := NO_LIBBIONIC=1
|
|||
make_no_auxtrace := NO_AUXTRACE=1
|
||||
make_no_libbpf := NO_LIBBPF=1
|
||||
make_no_libcrypto := NO_LIBCRYPTO=1
|
||||
make_with_babeltrace:= LIBBABELTRACE=1
|
||||
make_tags := tags
|
||||
make_cscope := cscope
|
||||
make_help := help
|
||||
|
@ -136,6 +137,7 @@ run += make_no_libaudit
|
|||
run += make_no_libbionic
|
||||
run += make_no_auxtrace
|
||||
run += make_no_libbpf
|
||||
run += make_with_babeltrace
|
||||
run += make_help
|
||||
run += make_doc
|
||||
run += make_perf_o
|
||||
|
|
|
@ -223,16 +223,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
|||
} else if (ins__is_call(dl->ins)) {
|
||||
ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
|
||||
SLsmg_write_char(' ');
|
||||
} else if (ins__is_ret(dl->ins)) {
|
||||
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
|
||||
SLsmg_write_char(' ');
|
||||
} else {
|
||||
ui_browser__write_nstring(browser, " ", 2);
|
||||
}
|
||||
} else {
|
||||
if (strcmp(dl->name, "retq")) {
|
||||
ui_browser__write_nstring(browser, " ", 2);
|
||||
} else {
|
||||
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
|
||||
SLsmg_write_char(' ');
|
||||
}
|
||||
ui_browser__write_nstring(browser, " ", 2);
|
||||
}
|
||||
|
||||
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
|
||||
|
@ -843,14 +841,14 @@ static int annotate_browser__run(struct annotate_browser *browser,
|
|||
ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
|
||||
else if (browser->selection->offset == -1)
|
||||
ui_helpline__puts("Actions are only available for assembly lines.");
|
||||
else if (!browser->selection->ins) {
|
||||
if (strcmp(browser->selection->name, "retq"))
|
||||
goto show_sup_ins;
|
||||
else if (!browser->selection->ins)
|
||||
goto show_sup_ins;
|
||||
else if (ins__is_ret(browser->selection->ins))
|
||||
goto out;
|
||||
} else if (!(annotate_browser__jump(browser) ||
|
||||
else if (!(annotate_browser__jump(browser) ||
|
||||
annotate_browser__callq(browser, evsel, hbt))) {
|
||||
show_sup_ins:
|
||||
ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
|
||||
ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
|
||||
}
|
||||
continue;
|
||||
case 't':
|
||||
|
|
|
@ -354,6 +354,15 @@ static struct ins_ops nop_ops = {
|
|||
.scnprintf = nop__scnprintf,
|
||||
};
|
||||
|
||||
static struct ins_ops ret_ops = {
|
||||
.scnprintf = ins__raw_scnprintf,
|
||||
};
|
||||
|
||||
bool ins__is_ret(const struct ins *ins)
|
||||
{
|
||||
return ins->ops == &ret_ops;
|
||||
}
|
||||
|
||||
static struct ins instructions[] = {
|
||||
{ .name = "add", .ops = &mov_ops, },
|
||||
{ .name = "addl", .ops = &mov_ops, },
|
||||
|
@ -444,6 +453,7 @@ static struct ins instructions[] = {
|
|||
{ .name = "xadd", .ops = &mov_ops, },
|
||||
{ .name = "xbeginl", .ops = &jump_ops, },
|
||||
{ .name = "xbeginq", .ops = &jump_ops, },
|
||||
{ .name = "retq", .ops = &ret_ops, },
|
||||
};
|
||||
|
||||
static int ins__key_cmp(const void *name, const void *insp)
|
||||
|
@ -1676,11 +1686,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hist_entry__annotate(struct hist_entry *he, size_t privsize)
|
||||
{
|
||||
return symbol__annotate(he->ms.sym, he->ms.map, privsize);
|
||||
}
|
||||
|
||||
bool ui__has_annotation(void)
|
||||
{
|
||||
return use_browser == 1 && perf_hpp_list.sym;
|
||||
|
|
|
@ -48,6 +48,7 @@ struct ins {
|
|||
|
||||
bool ins__is_jump(const struct ins *ins);
|
||||
bool ins__is_call(const struct ins *ins);
|
||||
bool ins__is_ret(const struct ins *ins);
|
||||
int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
|
||||
|
||||
struct annotation;
|
||||
|
@ -156,8 +157,6 @@ void symbol__annotate_zero_histograms(struct symbol *sym);
|
|||
|
||||
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
|
||||
|
||||
int hist_entry__annotate(struct hist_entry *he, size_t privsize);
|
||||
|
||||
int symbol__annotate_init(struct map *map, struct symbol *sym);
|
||||
int symbol__annotate_printf(struct symbol *sym, struct map *map,
|
||||
struct perf_evsel *evsel, bool full_paths,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "evlist.h"
|
||||
#include "evsel.h"
|
||||
#include "machine.h"
|
||||
#include "config.h"
|
||||
|
||||
#define pr_N(n, fmt, ...) \
|
||||
eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
|
||||
|
@ -68,6 +69,9 @@ struct ctf_writer {
|
|||
};
|
||||
struct bt_ctf_field_type *array[6];
|
||||
} data;
|
||||
struct bt_ctf_event_class *comm_class;
|
||||
struct bt_ctf_event_class *exit_class;
|
||||
struct bt_ctf_event_class *fork_class;
|
||||
};
|
||||
|
||||
struct convert {
|
||||
|
@ -76,6 +80,7 @@ struct convert {
|
|||
|
||||
u64 events_size;
|
||||
u64 events_count;
|
||||
u64 non_sample_count;
|
||||
|
||||
/* Ordered events configured queue size. */
|
||||
u64 queue_size;
|
||||
|
@ -140,6 +145,36 @@ FUNC_VALUE_SET(s64)
|
|||
FUNC_VALUE_SET(u64)
|
||||
__FUNC_VALUE_SET(u64_hex, u64)
|
||||
|
||||
static int string_set_value(struct bt_ctf_field *field, const char *string);
|
||||
static __maybe_unused int
|
||||
value_set_string(struct ctf_writer *cw, struct bt_ctf_event *event,
|
||||
const char *name, const char *string)
|
||||
{
|
||||
struct bt_ctf_field_type *type = cw->data.string;
|
||||
struct bt_ctf_field *field;
|
||||
int ret = 0;
|
||||
|
||||
field = bt_ctf_field_create(type);
|
||||
if (!field) {
|
||||
pr_err("failed to create a field %s\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = string_set_value(field, string);
|
||||
if (ret) {
|
||||
pr_err("failed to set value %s\n", name);
|
||||
goto err_put_field;
|
||||
}
|
||||
|
||||
ret = bt_ctf_event_set_payload(event, name, field);
|
||||
if (ret)
|
||||
pr_err("failed to set payload %s\n", name);
|
||||
|
||||
err_put_field:
|
||||
bt_ctf_field_put(field);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct bt_ctf_field_type*
|
||||
get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
|
||||
{
|
||||
|
@ -731,6 +766,72 @@ static int process_sample_event(struct perf_tool *tool,
|
|||
return cs ? 0 : -1;
|
||||
}
|
||||
|
||||
#define __NON_SAMPLE_SET_FIELD(_name, _type, _field) \
|
||||
do { \
|
||||
ret = value_set_##_type(cw, event, #_field, _event->_name._field);\
|
||||
if (ret) \
|
||||
return -1; \
|
||||
} while(0)
|
||||
|
||||
#define __FUNC_PROCESS_NON_SAMPLE(_name, body) \
|
||||
static int process_##_name##_event(struct perf_tool *tool, \
|
||||
union perf_event *_event, \
|
||||
struct perf_sample *sample, \
|
||||
struct machine *machine) \
|
||||
{ \
|
||||
struct convert *c = container_of(tool, struct convert, tool);\
|
||||
struct ctf_writer *cw = &c->writer; \
|
||||
struct bt_ctf_event_class *event_class = cw->_name##_class;\
|
||||
struct bt_ctf_event *event; \
|
||||
struct ctf_stream *cs; \
|
||||
int ret; \
|
||||
\
|
||||
c->non_sample_count++; \
|
||||
c->events_size += _event->header.size; \
|
||||
event = bt_ctf_event_create(event_class); \
|
||||
if (!event) { \
|
||||
pr_err("Failed to create an CTF event\n"); \
|
||||
return -1; \
|
||||
} \
|
||||
\
|
||||
bt_ctf_clock_set_time(cw->clock, sample->time); \
|
||||
body \
|
||||
cs = ctf_stream(cw, 0); \
|
||||
if (cs) { \
|
||||
if (is_flush_needed(cs)) \
|
||||
ctf_stream__flush(cs); \
|
||||
\
|
||||
cs->count++; \
|
||||
bt_ctf_stream_append_event(cs->stream, event); \
|
||||
} \
|
||||
bt_ctf_event_put(event); \
|
||||
\
|
||||
return perf_event__process_##_name(tool, _event, sample, machine);\
|
||||
}
|
||||
|
||||
__FUNC_PROCESS_NON_SAMPLE(comm,
|
||||
__NON_SAMPLE_SET_FIELD(comm, u32, pid);
|
||||
__NON_SAMPLE_SET_FIELD(comm, u32, tid);
|
||||
__NON_SAMPLE_SET_FIELD(comm, string, comm);
|
||||
)
|
||||
__FUNC_PROCESS_NON_SAMPLE(fork,
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, pid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, ppid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, tid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, ptid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u64, time);
|
||||
)
|
||||
|
||||
__FUNC_PROCESS_NON_SAMPLE(exit,
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, pid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, ppid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, tid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u32, ptid);
|
||||
__NON_SAMPLE_SET_FIELD(fork, u64, time);
|
||||
)
|
||||
#undef __NON_SAMPLE_SET_FIELD
|
||||
#undef __FUNC_PROCESS_NON_SAMPLE
|
||||
|
||||
/* If dup < 0, add a prefix. Else, add _dupl_X suffix. */
|
||||
static char *change_name(char *name, char *orig_name, int dup)
|
||||
{
|
||||
|
@ -1005,6 +1106,80 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define __NON_SAMPLE_ADD_FIELD(t, n) \
|
||||
do { \
|
||||
pr2(" field '%s'\n", #n); \
|
||||
if (bt_ctf_event_class_add_field(event_class, cw->data.t, #n)) {\
|
||||
pr_err("Failed to add field '%s';\n", #n);\
|
||||
return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(_name, body) \
|
||||
static int add_##_name##_event(struct ctf_writer *cw) \
|
||||
{ \
|
||||
struct bt_ctf_event_class *event_class; \
|
||||
int ret; \
|
||||
\
|
||||
pr("Adding "#_name" event\n"); \
|
||||
event_class = bt_ctf_event_class_create("perf_" #_name);\
|
||||
if (!event_class) \
|
||||
return -1; \
|
||||
body \
|
||||
\
|
||||
ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);\
|
||||
if (ret) { \
|
||||
pr("Failed to add event class '"#_name"' into stream.\n");\
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
cw->_name##_class = event_class; \
|
||||
bt_ctf_event_class_put(event_class); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(comm,
|
||||
__NON_SAMPLE_ADD_FIELD(u32, pid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, tid);
|
||||
__NON_SAMPLE_ADD_FIELD(string, comm);
|
||||
)
|
||||
|
||||
__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(fork,
|
||||
__NON_SAMPLE_ADD_FIELD(u32, pid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, ppid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, tid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, ptid);
|
||||
__NON_SAMPLE_ADD_FIELD(u64, time);
|
||||
)
|
||||
|
||||
__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(exit,
|
||||
__NON_SAMPLE_ADD_FIELD(u32, pid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, ppid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, tid);
|
||||
__NON_SAMPLE_ADD_FIELD(u32, ptid);
|
||||
__NON_SAMPLE_ADD_FIELD(u64, time);
|
||||
)
|
||||
|
||||
#undef __NON_SAMPLE_ADD_FIELD
|
||||
#undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS
|
||||
|
||||
static int setup_non_sample_events(struct ctf_writer *cw,
|
||||
struct perf_session *session __maybe_unused)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = add_comm_event(cw);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = add_exit_event(cw);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = add_fork_event(cw);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup_events(struct perf_session *session)
|
||||
{
|
||||
struct perf_evlist *evlist = session->evlist;
|
||||
|
@ -1273,13 +1448,14 @@ static int convert__config(const char *var, const char *value, void *cb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
||||
int bt_convert__perf2ctf(const char *input, const char *path,
|
||||
struct perf_data_convert_opts *opts)
|
||||
{
|
||||
struct perf_session *session;
|
||||
struct perf_data_file file = {
|
||||
.path = input,
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = force,
|
||||
.force = opts->force,
|
||||
};
|
||||
struct convert c = {
|
||||
.tool = {
|
||||
|
@ -1299,6 +1475,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
|||
struct ctf_writer *cw = &c.writer;
|
||||
int err = -1;
|
||||
|
||||
if (opts->all) {
|
||||
c.tool.comm = process_comm_event;
|
||||
c.tool.exit = process_exit_event;
|
||||
c.tool.fork = process_fork_event;
|
||||
}
|
||||
|
||||
perf_config(convert__config, &c);
|
||||
|
||||
/* CTF writer */
|
||||
|
@ -1323,6 +1505,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
|||
if (setup_events(cw, session))
|
||||
goto free_session;
|
||||
|
||||
if (opts->all && setup_non_sample_events(cw, session))
|
||||
goto free_session;
|
||||
|
||||
if (setup_streams(cw, session))
|
||||
goto free_session;
|
||||
|
||||
|
@ -1337,10 +1522,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
|||
file.path, path);
|
||||
|
||||
fprintf(stderr,
|
||||
"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
|
||||
"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples",
|
||||
(double) c.events_size / 1024.0 / 1024.0,
|
||||
c.events_count);
|
||||
|
||||
if (!c.non_sample_count)
|
||||
fprintf(stderr, ") ]\n");
|
||||
else
|
||||
fprintf(stderr, ", %" PRIu64 " non-samples) ]\n", c.non_sample_count);
|
||||
|
||||
cleanup_events(session);
|
||||
perf_session__delete(session);
|
||||
ctf_writer__cleanup(cw);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef __DATA_CONVERT_BT_H
|
||||
#define __DATA_CONVERT_BT_H
|
||||
#include "data-convert.h"
|
||||
#ifdef HAVE_LIBBABELTRACE_SUPPORT
|
||||
|
||||
int bt_convert__perf2ctf(const char *input_name, const char *to_ctf, bool force);
|
||||
int bt_convert__perf2ctf(const char *input_name, const char *to_ctf,
|
||||
struct perf_data_convert_opts *opts);
|
||||
|
||||
#endif /* HAVE_LIBBABELTRACE_SUPPORT */
|
||||
#endif /* __DATA_CONVERT_BT_H */
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __DATA_CONVERT_H
|
||||
#define __DATA_CONVERT_H
|
||||
|
||||
struct perf_data_convert_opts {
|
||||
bool force;
|
||||
bool all;
|
||||
};
|
||||
|
||||
#endif /* __DATA_CONVERT_H */
|
|
@ -1430,7 +1430,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
|||
* Read the build id if possible. This is required for
|
||||
* DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
|
||||
*/
|
||||
if (is_regular_file(name) &&
|
||||
if (is_regular_file(dso->long_name) &&
|
||||
filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
|
||||
dso__set_build_id(dso, build_id);
|
||||
|
||||
|
|
Loading…
Reference in New Issue