Commit d905768c authored by Ingo Molnar's avatar Ingo Molnar

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

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents d4cf1949 ebccba3f
...@@ -34,6 +34,10 @@ OPTIONS for 'convert' ...@@ -34,6 +34,10 @@ OPTIONS for 'convert'
--verbose:: --verbose::
Be more verbose (show counter open errors, etc). 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 SEE ALSO
-------- --------
linkperf:perf[1] linkperf:perf[1]
......
...@@ -9,34 +9,44 @@ const char *const arm_triplets[] = { ...@@ -9,34 +9,44 @@ const char *const arm_triplets[] = {
"arm-unknown-linux-", "arm-unknown-linux-",
"arm-unknown-linux-gnu-", "arm-unknown-linux-gnu-",
"arm-unknown-linux-gnueabi-", "arm-unknown-linux-gnueabi-",
"arm-linux-gnu-",
"arm-linux-gnueabihf-",
"arm-none-eabi-",
NULL NULL
}; };
const char *const arm64_triplets[] = { const char *const arm64_triplets[] = {
"aarch64-linux-android-", "aarch64-linux-android-",
"aarch64-linux-gnu-",
NULL NULL
}; };
const char *const powerpc_triplets[] = { const char *const powerpc_triplets[] = {
"powerpc-unknown-linux-gnu-", "powerpc-unknown-linux-gnu-",
"powerpc64-unknown-linux-gnu-", "powerpc64-unknown-linux-gnu-",
"powerpc64-linux-gnu-",
"powerpc64le-linux-gnu-",
NULL NULL
}; };
const char *const s390_triplets[] = { const char *const s390_triplets[] = {
"s390-ibm-linux-", "s390-ibm-linux-",
"s390x-linux-gnu-",
NULL NULL
}; };
const char *const sh_triplets[] = { const char *const sh_triplets[] = {
"sh-unknown-linux-gnu-", "sh-unknown-linux-gnu-",
"sh64-unknown-linux-gnu-", "sh64-unknown-linux-gnu-",
"sh-linux-gnu-",
"sh64-linux-gnu-",
NULL NULL
}; };
const char *const sparc_triplets[] = { const char *const sparc_triplets[] = {
"sparc-unknown-linux-gnu-", "sparc-unknown-linux-gnu-",
"sparc64-unknown-linux-gnu-", "sparc64-unknown-linux-gnu-",
"sparc64-linux-gnu-",
NULL NULL
}; };
...@@ -49,12 +59,19 @@ const char *const x86_triplets[] = { ...@@ -49,12 +59,19 @@ const char *const x86_triplets[] = {
"i386-pc-linux-gnu-", "i386-pc-linux-gnu-",
"i686-linux-android-", "i686-linux-android-",
"i686-android-linux-", "i686-android-linux-",
"x86_64-linux-gnu-",
"i586-linux-gnu-",
NULL NULL
}; };
const char *const mips_triplets[] = { const char *const mips_triplets[] = {
"mips-unknown-linux-gnu-", "mips-unknown-linux-gnu-",
"mipsel-linux-android-", "mipsel-linux-android-",
"mips-linux-gnu-",
"mips64-linux-gnu-",
"mips64el-linux-gnuabi64-",
"mips64-linux-gnuabi64-",
"mipsel-linux-gnu-",
NULL NULL
}; };
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "perf.h" #include "perf.h"
#include "debug.h" #include "debug.h"
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
#include "data-convert.h"
#include "data-convert-bt.h" #include "data-convert-bt.h"
typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); 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, ...@@ -53,14 +54,18 @@ static int cmd_data_convert(int argc, const char **argv,
const char *prefix __maybe_unused) const char *prefix __maybe_unused)
{ {
const char *to_ctf = NULL; const char *to_ctf = NULL;
bool force = false; struct perf_data_convert_opts opts = {
.force = false,
.all = false,
};
const struct option options[] = { const struct option options[] = {
OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_INCR('v', "verbose", &verbose, "be more verbose"),
OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_STRING('i', "input", &input_name, "file", "input file name"),
#ifdef HAVE_LIBBABELTRACE_SUPPORT #ifdef HAVE_LIBBABELTRACE_SUPPORT
OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"),
#endif #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() OPT_END()
}; };
...@@ -78,7 +83,7 @@ static int cmd_data_convert(int argc, const char **argv, ...@@ -78,7 +83,7 @@ static int cmd_data_convert(int argc, const char **argv,
if (to_ctf) { if (to_ctf) {
#ifdef HAVE_LIBBABELTRACE_SUPPORT #ifdef HAVE_LIBBABELTRACE_SUPPORT
return bt_convert__perf2ctf(input_name, to_ctf, force); return bt_convert__perf2ctf(input_name, to_ctf, &opts);
#else #else
pr_err("The libbabeltrace support is not compiled in.\n"); pr_err("The libbabeltrace support is not compiled in.\n");
return -1; return -1;
......
...@@ -132,9 +132,9 @@ rb_find_range(struct perf_evlist *evlist, ...@@ -132,9 +132,9 @@ rb_find_range(struct perf_evlist *evlist,
return backward_rb_find_range(data, mask, head, start, end); 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 head = perf_mmap__read_head(md);
u64 old = md->prev; u64 old = md->prev;
u64 end = head, start = old; u64 end = head, start = old;
...@@ -143,7 +143,7 @@ static int record__mmap_read(struct record *rec, int idx) ...@@ -143,7 +143,7 @@ static int record__mmap_read(struct record *rec, int idx)
void *buf; void *buf;
int rc = 0; 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)) old, &start, &end))
return -1; return -1;
...@@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, int idx) ...@@ -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"); WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
md->prev = head; md->prev = head;
perf_evlist__mmap_consume(rec->evlist, idx); perf_evlist__mmap_consume(evlist, idx);
return 0; return 0;
} }
...@@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, int idx) ...@@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, int idx)
} }
md->prev = head; md->prev = head;
perf_evlist__mmap_consume(rec->evlist, idx); perf_evlist__mmap_consume(evlist, idx);
out: out:
return rc; return rc;
} }
...@@ -342,6 +342,40 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused) ...@@ -342,6 +342,40 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
#endif #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) static int record__open(struct record *rec)
{ {
char msg[512]; char msg[512];
...@@ -378,27 +412,9 @@ static int record__open(struct record *rec) ...@@ -378,27 +412,9 @@ static int record__open(struct record *rec)
goto out; goto out;
} }
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, rc = record__mmap(rec);
opts->auxtrace_mmap_pages, if (rc)
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;
}
goto out; goto out;
}
session->evlist = evlist; session->evlist = evlist;
perf_session__set_id_hdr_size(session); perf_session__set_id_hdr_size(session);
...@@ -482,17 +498,20 @@ static struct perf_event_header finished_round_event = { ...@@ -482,17 +498,20 @@ static struct perf_event_header finished_round_event = {
.type = PERF_RECORD_FINISHED_ROUND, .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; u64 bytes_written = rec->bytes_written;
int i; int i;
int rc = 0; int rc = 0;
for (i = 0; i < rec->evlist->nr_mmaps; i++) { if (!evlist)
struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap; return 0;
if (rec->evlist->mmap[i].base) { for (i = 0; i < evlist->nr_mmaps; i++) {
if (record__mmap_read(rec, i) != 0) { struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap;
if (evlist->mmap[i].base) {
if (record__mmap_read(rec, evlist, i) != 0) {
rc = -1; rc = -1;
goto out; goto out;
} }
...@@ -516,6 +535,17 @@ static int record__mmap_read_all(struct record *rec) ...@@ -516,6 +535,17 @@ static int record__mmap_read_all(struct record *rec)
return rc; 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) static void record__init_features(struct record *rec)
{ {
struct perf_session *session = rec->session; struct perf_session *session = rec->session;
...@@ -656,10 +686,21 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused ...@@ -656,10 +686,21 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused
return 0; 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) static const struct perf_event_mmap_page *record__pick_pc(struct record *rec)
{ {
if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base) const struct perf_event_mmap_page *pc;
return rec->evlist->mmap[0].base;
pc = perf_evlist__pick_pc(rec->evlist);
if (pc)
return pc;
return NULL; return NULL;
} }
......
...@@ -482,7 +482,7 @@ endif ...@@ -482,7 +482,7 @@ endif
ifndef NO_SLANG ifndef NO_SLANG
ifneq ($(feature-libslang), 1) 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 NO_SLANG := 1
else else
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
......
...@@ -81,6 +81,7 @@ make_no_libbionic := NO_LIBBIONIC=1 ...@@ -81,6 +81,7 @@ make_no_libbionic := NO_LIBBIONIC=1
make_no_auxtrace := NO_AUXTRACE=1 make_no_auxtrace := NO_AUXTRACE=1
make_no_libbpf := NO_LIBBPF=1 make_no_libbpf := NO_LIBBPF=1
make_no_libcrypto := NO_LIBCRYPTO=1 make_no_libcrypto := NO_LIBCRYPTO=1
make_with_babeltrace:= LIBBABELTRACE=1
make_tags := tags make_tags := tags
make_cscope := cscope make_cscope := cscope
make_help := help make_help := help
...@@ -136,6 +137,7 @@ run += make_no_libaudit ...@@ -136,6 +137,7 @@ run += make_no_libaudit
run += make_no_libbionic run += make_no_libbionic
run += make_no_auxtrace run += make_no_auxtrace
run += make_no_libbpf run += make_no_libbpf
run += make_with_babeltrace
run += make_help run += make_help
run += make_doc run += make_doc
run += make_perf_o run += make_perf_o
......
...@@ -223,16 +223,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ...@@ -223,16 +223,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
} else if (ins__is_call(dl->ins)) { } else if (ins__is_call(dl->ins)) {
ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
SLsmg_write_char(' '); SLsmg_write_char(' ');
} else if (ins__is_ret(dl->ins)) {
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
SLsmg_write_char(' ');
} else { } else {
ui_browser__write_nstring(browser, " ", 2); ui_browser__write_nstring(browser, " ", 2);
} }
} else { } else {
if (strcmp(dl->name, "retq")) { ui_browser__write_nstring(browser, " ", 2);
ui_browser__write_nstring(browser, " ", 2);
} else {
ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
SLsmg_write_char(' ');
}
} }
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 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, ...@@ -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"); ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
else if (browser->selection->offset == -1) else if (browser->selection->offset == -1)
ui_helpline__puts("Actions are only available for assembly lines."); ui_helpline__puts("Actions are only available for assembly lines.");
else if (!browser->selection->ins) { else if (!browser->selection->ins)
if (strcmp(browser->selection->name, "retq")) goto show_sup_ins;
goto show_sup_ins; else if (ins__is_ret(browser->selection->ins))
goto out; goto out;
} else if (!(annotate_browser__jump(browser) || else if (!(annotate_browser__jump(browser) ||
annotate_browser__callq(browser, evsel, hbt))) { annotate_browser__callq(browser, evsel, hbt))) {
show_sup_ins: 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; continue;
case 't': case 't':
......
...@@ -354,6 +354,15 @@ static struct ins_ops nop_ops = { ...@@ -354,6 +354,15 @@ static struct ins_ops nop_ops = {
.scnprintf = nop__scnprintf, .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[] = { static struct ins instructions[] = {
{ .name = "add", .ops = &mov_ops, }, { .name = "add", .ops = &mov_ops, },
{ .name = "addl", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, },
...@@ -444,6 +453,7 @@ static struct ins instructions[] = { ...@@ -444,6 +453,7 @@ static struct ins instructions[] = {
{ .name = "xadd", .ops = &mov_ops, }, { .name = "xadd", .ops = &mov_ops, },
{ .name = "xbeginl", .ops = &jump_ops, }, { .name = "xbeginl", .ops = &jump_ops, },
{ .name = "xbeginq", .ops = &jump_ops, }, { .name = "xbeginq", .ops = &jump_ops, },
{ .name = "retq", .ops = &ret_ops, },
}; };
static int ins__key_cmp(const void *name, const void *insp) 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, ...@@ -1676,11 +1686,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
return 0; 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) bool ui__has_annotation(void)
{ {
return use_browser == 1 && perf_hpp_list.sym; return use_browser == 1 && perf_hpp_list.sym;
......
...@@ -48,6 +48,7 @@ struct ins { ...@@ -48,6 +48,7 @@ struct ins {
bool ins__is_jump(const struct ins *ins); bool ins__is_jump(const struct ins *ins);
bool ins__is_call(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); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
struct annotation; struct annotation;
...@@ -156,8 +157,6 @@ void symbol__annotate_zero_histograms(struct symbol *sym); ...@@ -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 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_init(struct map *map, struct symbol *sym);
int symbol__annotate_printf(struct symbol *sym, struct map *map, int symbol__annotate_printf(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool full_paths, struct perf_evsel *evsel, bool full_paths,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "evlist.h" #include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include "machine.h" #include "machine.h"
#include "config.h"
#define pr_N(n, fmt, ...) \ #define pr_N(n, fmt, ...) \
eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
...@@ -68,6 +69,9 @@ struct ctf_writer { ...@@ -68,6 +69,9 @@ struct ctf_writer {
}; };
struct bt_ctf_field_type *array[6]; struct bt_ctf_field_type *array[6];
} data; } data;
struct bt_ctf_event_class *comm_class;
struct bt_ctf_event_class *exit_class;
struct bt_ctf_event_class *fork_class;
}; };
struct convert { struct convert {
...@@ -76,6 +80,7 @@ struct convert { ...@@ -76,6 +80,7 @@ struct convert {
u64 events_size; u64 events_size;
u64 events_count; u64 events_count;
u64 non_sample_count;
/* Ordered events configured queue size. */ /* Ordered events configured queue size. */
u64 queue_size; u64 queue_size;
...@@ -140,6 +145,36 @@ FUNC_VALUE_SET(s64) ...@@ -140,6 +145,36 @@ FUNC_VALUE_SET(s64)
FUNC_VALUE_SET(u64) FUNC_VALUE_SET(u64)
__FUNC_VALUE_SET(u64_hex, 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* static struct bt_ctf_field_type*
get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) 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, ...@@ -731,6 +766,72 @@ static int process_sample_event(struct perf_tool *tool,
return cs ? 0 : -1; 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. */ /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */
static char *change_name(char *name, char *orig_name, int dup) 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) ...@@ -1005,6 +1106,80 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
return 0; 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) static void cleanup_events(struct perf_session *session)
{ {
struct perf_evlist *evlist = session->evlist; struct perf_evlist *evlist = session->evlist;
...@@ -1273,13 +1448,14 @@ static int convert__config(const char *var, const char *value, void *cb) ...@@ -1273,13 +1448,14 @@ static int convert__config(const char *var, const char *value, void *cb)
return 0; 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_session *session;
struct perf_data_file file = { struct perf_data_file file = {
.path = input, .path = input,
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
.force = force, .force = opts->force,
}; };
struct convert c = { struct convert c = {
.tool = { .tool = {
...@@ -1299,6 +1475,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) ...@@ -1299,6 +1475,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
struct ctf_writer *cw = &c.writer; struct ctf_writer *cw = &c.writer;
int err = -1; 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); perf_config(convert__config, &c);
/* CTF writer */ /* CTF writer */
...@@ -1323,6 +1505,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) ...@@ -1323,6 +1505,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
if (setup_events(cw, session)) if (setup_events(cw, session))
goto free_session; goto free_session;
if (opts->all && setup_non_sample_events(cw, session))
goto free_session;
if (setup_streams(cw, session)) if (setup_streams(cw, session))
goto free_session; goto free_session;
...@@ -1337,10 +1522,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) ...@@ -1337,10 +1522,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
file.path, path); file.path, path);
fprintf(stderr, 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, (double) c.events_size / 1024.0 / 1024.0,
c.events_count); 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); cleanup_events(session);
perf_session__delete(session); perf_session__delete(session);
ctf_writer__cleanup(cw); ctf_writer__cleanup(cw);
......
#ifndef __DATA_CONVERT_BT_H #ifndef __DATA_CONVERT_BT_H
#define __DATA_CONVERT_BT_H #define __DATA_CONVERT_BT_H
#include "data-convert.h"
#ifdef HAVE_LIBBABELTRACE_SUPPORT #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 /* HAVE_LIBBABELTRACE_SUPPORT */
#endif /* __DATA_CONVERT_BT_H */ #endif /* __DATA_CONVERT_BT_H */
#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) ...@@ -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 * Read the build id if possible. This is required for
* DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work * 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) filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
dso__set_build_id(dso, build_id); dso__set_build_id(dso, build_id);
......
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