From 44b3802122174ba499613bac3aab2e66e948ce1e Mon Sep 17 00:00:00 2001 From: Alexander Yarygin Date: Thu, 3 Jul 2014 18:29:04 +0400 Subject: [PATCH 01/33] perf kvm: Use defines of kvm events Currently perf-kvm uses string literals for kvm event names, but it works only for x86, because other architectures may have other names for those events. To reduce dependence on architecture, we add file with defines for: - kvm_entry and kvm_exit events, - exit reason field name in kvm_exit event, - length of exit reasons strings, - vcpu_id field name in kvm trace events, and replace literals in perf-kvm. Reviewed-by: Cornelia Huck Reviewed-by David Ahern Signed-off-by: Alexander Yarygin Acked-by: Christian Borntraeger Cc: Christian Borntraeger Cc: Cornelia Huck Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1404397747-20939-2-git-send-email-yarygin@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/include/uapi/asm/Kbuild | 1 + arch/x86/include/uapi/asm/kvm_perf.h | 16 +++++++++++++ tools/perf/MANIFEST | 1 + tools/perf/builtin-kvm.c | 34 +++++++++++++--------------- 4 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 arch/x86/include/uapi/asm/kvm_perf.h diff --git a/arch/x86/include/uapi/asm/Kbuild b/arch/x86/include/uapi/asm/Kbuild index 09409c44f9a5..3dec769cadf7 100644 --- a/arch/x86/include/uapi/asm/Kbuild +++ b/arch/x86/include/uapi/asm/Kbuild @@ -22,6 +22,7 @@ header-y += ipcbuf.h header-y += ist.h header-y += kvm.h header-y += kvm_para.h +header-y += kvm_perf.h header-y += ldt.h header-y += mce.h header-y += mman.h diff --git a/arch/x86/include/uapi/asm/kvm_perf.h b/arch/x86/include/uapi/asm/kvm_perf.h new file mode 100644 index 000000000000..3bb964f88aa1 --- /dev/null +++ b/arch/x86/include/uapi/asm/kvm_perf.h @@ -0,0 +1,16 @@ +#ifndef _ASM_X86_KVM_PERF_H +#define _ASM_X86_KVM_PERF_H + +#include +#include +#include + +#define DECODE_STR_LEN 20 + +#define VCPU_ID "vcpu_id" + +#define KVM_ENTRY_TRACE "kvm:kvm_entry" +#define KVM_EXIT_TRACE "kvm:kvm_exit" +#define KVM_EXIT_REASON "exit_reason" + +#endif /* _ASM_X86_KVM_PERF_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 45da209b6ed3..02b485d619cd 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -37,3 +37,4 @@ arch/x86/include/asm/kvm_host.h arch/x86/include/uapi/asm/svm.h arch/x86/include/uapi/asm/vmx.h arch/x86/include/uapi/asm/kvm.h +arch/x86/include/uapi/asm/kvm_perf.h diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 41dbeaf8cc11..6d73346ef2a6 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -30,9 +30,7 @@ #include #ifdef HAVE_KVM_STAT_SUPPORT -#include -#include -#include +#include struct event_key { #define INVALID_KEY (~0ULL) @@ -75,7 +73,7 @@ struct kvm_events_ops { bool (*is_end_event)(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key); void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, - char decode[20]); + char *decode); const char *name; }; @@ -126,12 +124,12 @@ static void exit_event_get_key(struct perf_evsel *evsel, struct event_key *key) { key->info = 0; - key->key = perf_evsel__intval(evsel, sample, "exit_reason"); + key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); } static bool kvm_exit_event(struct perf_evsel *evsel) { - return !strcmp(evsel->name, "kvm:kvm_exit"); + return !strcmp(evsel->name, KVM_EXIT_TRACE); } static bool exit_event_begin(struct perf_evsel *evsel, @@ -147,7 +145,7 @@ static bool exit_event_begin(struct perf_evsel *evsel, static bool kvm_entry_event(struct perf_evsel *evsel) { - return !strcmp(evsel->name, "kvm:kvm_entry"); + return !strcmp(evsel->name, KVM_ENTRY_TRACE); } static bool exit_event_end(struct perf_evsel *evsel, @@ -182,12 +180,12 @@ static const char *get_exit_reason(struct perf_kvm_stat *kvm, static void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, - char decode[20]) + char *decode) { const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons, key->key); - scnprintf(decode, 20, "%s", exit_reason); + scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); } static struct kvm_events_ops exit_events = { @@ -249,9 +247,9 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, struct event_key *key, - char decode[20]) + char *decode) { - scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, + scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", (unsigned long)key->key, key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); } @@ -292,9 +290,9 @@ static bool ioport_event_end(struct perf_evsel *evsel, static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, struct event_key *key, - char decode[20]) + char *decode) { - scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, + scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", (unsigned long long)key->key, key->info ? "POUT" : "PIN"); } @@ -524,7 +522,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, time_diff = sample->time - time_begin; if (kvm->duration && time_diff > kvm->duration) { - char decode[32]; + char decode[DECODE_STR_LEN]; kvm->events_ops->decode_key(kvm, &event->key, decode); if (strcmp(decode, "HLT")) { @@ -552,7 +550,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, return NULL; } - vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); + vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); thread->priv = vcpu_record; } @@ -739,7 +737,7 @@ static void show_timeofday(void) static void print_result(struct perf_kvm_stat *kvm) { - char decode[20]; + char decode[DECODE_STR_LEN]; struct kvm_event *event; int vcpu = kvm->trace_vcpu; @@ -750,7 +748,7 @@ static void print_result(struct perf_kvm_stat *kvm) pr_info("\n\n"); print_vcpu_info(kvm); - pr_info("%20s ", kvm->events_ops->name); + pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name); pr_info("%10s ", "Samples"); pr_info("%9s ", "Samples%"); @@ -769,7 +767,7 @@ static void print_result(struct perf_kvm_stat *kvm) min = get_event_min(event, vcpu); kvm->events_ops->decode_key(kvm, &event->key, decode); - pr_info("%20s ", decode); + pr_info("%*s ", DECODE_STR_LEN, decode); pr_info("%10llu ", (unsigned long long)ecount); pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); From 9daa81239e60c162153fb2a365b8492c9a9bf632 Mon Sep 17 00:00:00 2001 From: Alexander Yarygin Date: Thu, 3 Jul 2014 18:29:05 +0400 Subject: [PATCH 02/33] perf kvm: Move arch specific code into arch/ Parts of a 'perf kvm stat' code make sense only for x86. Let's move this code into the arch/x86/kvm-stat.c file and add util/kvm-stat.h for generic structure definitions. Add a global array 'kvm_reg_events_ops' for accessing the arch-specific 'kvm_events_ops' from generic code. Since the several global arrays (i.e. 'kvm_events_tp') have been moved to arch/*, we can not know their sizes and use them directly in builtin-kvm.c. This patch fixes that problem by adding trimming NULL element to each array and changing the behavior of their handlers in generic code. Reviewed-by: David Ahern Reviewed-by: Cornelia Huck Signed-off-by: Alexander Yarygin Acked-by: Christian Borntraeger Cc: Christian Borntraeger Cc: Cornelia Huck Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1404397747-20939-3-git-send-email-yarygin@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 1 + tools/perf/arch/x86/Makefile | 1 + tools/perf/arch/x86/util/kvm-stat.c | 151 ++++++++++++++ tools/perf/builtin-kvm.c | 297 ++++------------------------ tools/perf/util/kvm-stat.h | 130 ++++++++++++ 5 files changed, 317 insertions(+), 263 deletions(-) create mode 100644 tools/perf/arch/x86/util/kvm-stat.c create mode 100644 tools/perf/util/kvm-stat.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 9670a16fa577..90c498378a54 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -300,6 +300,7 @@ LIB_H += ui/progress.h LIB_H += ui/util.h LIB_H += ui/ui.h LIB_H += util/data.h +LIB_H += util/kvm-stat.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index d3939014a877..9b21881db52f 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile @@ -16,3 +16,4 @@ LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o LIB_H += arch/$(ARCH)/util/tsc.h HAVE_KVM_STAT_SUPPORT := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c new file mode 100644 index 000000000000..2f8d2c1af5ca --- /dev/null +++ b/tools/perf/arch/x86/util/kvm-stat.c @@ -0,0 +1,151 @@ +#include "../../util/kvm-stat.h" +#include + +define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); +define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); + +static struct kvm_events_ops exit_events = { + .is_begin_event = exit_event_begin, + .is_end_event = exit_event_end, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + +/* + * For the mmio events, we treat: + * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry + * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). + */ +static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, + struct event_key *key) +{ + key->key = perf_evsel__intval(evsel, sample, "gpa"); + key->info = perf_evsel__intval(evsel, sample, "type"); +} + +#define KVM_TRACE_MMIO_READ_UNSATISFIED 0 +#define KVM_TRACE_MMIO_READ 1 +#define KVM_TRACE_MMIO_WRITE 2 + +static bool mmio_event_begin(struct perf_evsel *evsel, + struct perf_sample *sample, struct event_key *key) +{ + /* MMIO read begin event in kernel. */ + if (kvm_exit_event(evsel)) + return true; + + /* MMIO write begin event in kernel. */ + if (!strcmp(evsel->name, "kvm:kvm_mmio") && + perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { + mmio_event_get_key(evsel, sample, key); + return true; + } + + return false; +} + +static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, + struct event_key *key) +{ + /* MMIO write end event in kernel. */ + if (kvm_entry_event(evsel)) + return true; + + /* MMIO read end event in kernel.*/ + if (!strcmp(evsel->name, "kvm:kvm_mmio") && + perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { + mmio_event_get_key(evsel, sample, key); + return true; + } + + return false; +} + +static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, + struct event_key *key, + char *decode) +{ + scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", + (unsigned long)key->key, + key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); +} + +static struct kvm_events_ops mmio_events = { + .is_begin_event = mmio_event_begin, + .is_end_event = mmio_event_end, + .decode_key = mmio_event_decode_key, + .name = "MMIO Access" +}; + + /* The time of emulation pio access is from kvm_pio to kvm_entry. */ +static void ioport_event_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + key->key = perf_evsel__intval(evsel, sample, "port"); + key->info = perf_evsel__intval(evsel, sample, "rw"); +} + +static bool ioport_event_begin(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + if (!strcmp(evsel->name, "kvm:kvm_pio")) { + ioport_event_get_key(evsel, sample, key); + return true; + } + + return false; +} + +static bool ioport_event_end(struct perf_evsel *evsel, + struct perf_sample *sample __maybe_unused, + struct event_key *key __maybe_unused) +{ + return kvm_entry_event(evsel); +} + +static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, + struct event_key *key, + char *decode) +{ + scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", + (unsigned long long)key->key, + key->info ? "POUT" : "PIN"); +} + +static struct kvm_events_ops ioport_events = { + .is_begin_event = ioport_event_begin, + .is_end_event = ioport_event_end, + .decode_key = ioport_event_decode_key, + .name = "IO Port Access" +}; + +const char * const kvm_events_tp[] = { + "kvm:kvm_entry", + "kvm:kvm_exit", + "kvm:kvm_mmio", + "kvm:kvm_pio", + NULL, +}; + +struct kvm_reg_events_ops kvm_reg_events_ops[] = { + { .name = "vmexit", .ops = &exit_events }, + { .name = "mmio", .ops = &mmio_events }, + { .name = "ioport", .ops = &ioport_events }, + { NULL, NULL }, +}; + +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) +{ + if (strstr(cpuid, "Intel")) { + kvm->exit_reasons = vmx_exit_reasons; + kvm->exit_reasons_isa = "VMX"; + } else if (strstr(cpuid, "AMD")) { + kvm->exit_reasons = svm_exit_reasons; + kvm->exit_reasons_isa = "SVM"; + } else + return -ENOTSUP; + + return 0; +} diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 6d73346ef2a6..75ee8c1a6baf 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -31,109 +31,23 @@ #ifdef HAVE_KVM_STAT_SUPPORT #include +#include "util/kvm-stat.h" -struct event_key { - #define INVALID_KEY (~0ULL) - u64 key; - int info; -}; - -struct kvm_event_stats { - u64 time; - struct stats stats; -}; - -struct kvm_event { - struct list_head hash_entry; - struct rb_node rb; - - struct event_key key; - - struct kvm_event_stats total; - - #define DEFAULT_VCPU_NUM 8 - int max_vcpu; - struct kvm_event_stats *vcpu; -}; - -typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); - -struct kvm_event_key { - const char *name; - key_cmp_fun key; -}; - - -struct perf_kvm_stat; - -struct kvm_events_ops { - bool (*is_begin_event)(struct perf_evsel *evsel, - struct perf_sample *sample, - struct event_key *key); - bool (*is_end_event)(struct perf_evsel *evsel, - struct perf_sample *sample, struct event_key *key); - void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, - char *decode); - const char *name; -}; - -struct exit_reasons_table { - unsigned long exit_code; - const char *reason; -}; - -#define EVENTS_BITS 12 -#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) - -struct perf_kvm_stat { - struct perf_tool tool; - struct record_opts opts; - struct perf_evlist *evlist; - struct perf_session *session; - - const char *file_name; - const char *report_event; - const char *sort_key; - int trace_vcpu; - - struct exit_reasons_table *exit_reasons; - const char *exit_reasons_isa; - - struct kvm_events_ops *events_ops; - key_cmp_fun compare; - struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; - - u64 total_time; - u64 total_count; - u64 lost_events; - u64 duration; - - const char *pid_str; - struct intlist *pid_list; - - struct rb_root result; - - int timerfd; - unsigned int display_time; - bool live; -}; - - -static void exit_event_get_key(struct perf_evsel *evsel, - struct perf_sample *sample, - struct event_key *key) +void exit_event_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) { key->info = 0; key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); } -static bool kvm_exit_event(struct perf_evsel *evsel) +bool kvm_exit_event(struct perf_evsel *evsel) { return !strcmp(evsel->name, KVM_EXIT_TRACE); } -static bool exit_event_begin(struct perf_evsel *evsel, - struct perf_sample *sample, struct event_key *key) +bool exit_event_begin(struct perf_evsel *evsel, + struct perf_sample *sample, struct event_key *key) { if (kvm_exit_event(evsel)) { exit_event_get_key(evsel, sample, key); @@ -143,26 +57,18 @@ static bool exit_event_begin(struct perf_evsel *evsel, return false; } -static bool kvm_entry_event(struct perf_evsel *evsel) +bool kvm_entry_event(struct perf_evsel *evsel) { return !strcmp(evsel->name, KVM_ENTRY_TRACE); } -static bool exit_event_end(struct perf_evsel *evsel, - struct perf_sample *sample __maybe_unused, - struct event_key *key __maybe_unused) +bool exit_event_end(struct perf_evsel *evsel, + struct perf_sample *sample __maybe_unused, + struct event_key *key __maybe_unused) { return kvm_entry_event(evsel); } -#define define_exit_reasons_table(name, symbols) \ - static struct exit_reasons_table name[] = { \ - symbols, { -1, NULL } \ - } - -define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); -define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); - static const char *get_exit_reason(struct perf_kvm_stat *kvm, struct exit_reasons_table *tbl, u64 exit_code) @@ -178,9 +84,9 @@ static const char *get_exit_reason(struct perf_kvm_stat *kvm, return "UNKNOWN"; } -static void exit_event_decode_key(struct perf_kvm_stat *kvm, - struct event_key *key, - char *decode) +void exit_event_decode_key(struct perf_kvm_stat *kvm, + struct event_key *key, + char *decode) { const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons, key->key); @@ -188,137 +94,18 @@ static void exit_event_decode_key(struct perf_kvm_stat *kvm, scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); } -static struct kvm_events_ops exit_events = { - .is_begin_event = exit_event_begin, - .is_end_event = exit_event_end, - .decode_key = exit_event_decode_key, - .name = "VM-EXIT" -}; - -/* - * For the mmio events, we treat: - * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry - * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). - */ -static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, - struct event_key *key) -{ - key->key = perf_evsel__intval(evsel, sample, "gpa"); - key->info = perf_evsel__intval(evsel, sample, "type"); -} - -#define KVM_TRACE_MMIO_READ_UNSATISFIED 0 -#define KVM_TRACE_MMIO_READ 1 -#define KVM_TRACE_MMIO_WRITE 2 - -static bool mmio_event_begin(struct perf_evsel *evsel, - struct perf_sample *sample, struct event_key *key) -{ - /* MMIO read begin event in kernel. */ - if (kvm_exit_event(evsel)) - return true; - - /* MMIO write begin event in kernel. */ - if (!strcmp(evsel->name, "kvm:kvm_mmio") && - perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { - mmio_event_get_key(evsel, sample, key); - return true; - } - - return false; -} - -static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, - struct event_key *key) -{ - /* MMIO write end event in kernel. */ - if (kvm_entry_event(evsel)) - return true; - - /* MMIO read end event in kernel.*/ - if (!strcmp(evsel->name, "kvm:kvm_mmio") && - perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { - mmio_event_get_key(evsel, sample, key); - return true; - } - - return false; -} - -static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, - struct event_key *key, - char *decode) -{ - scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", (unsigned long)key->key, - key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); -} - -static struct kvm_events_ops mmio_events = { - .is_begin_event = mmio_event_begin, - .is_end_event = mmio_event_end, - .decode_key = mmio_event_decode_key, - .name = "MMIO Access" -}; - - /* The time of emulation pio access is from kvm_pio to kvm_entry. */ -static void ioport_event_get_key(struct perf_evsel *evsel, - struct perf_sample *sample, - struct event_key *key) -{ - key->key = perf_evsel__intval(evsel, sample, "port"); - key->info = perf_evsel__intval(evsel, sample, "rw"); -} - -static bool ioport_event_begin(struct perf_evsel *evsel, - struct perf_sample *sample, - struct event_key *key) -{ - if (!strcmp(evsel->name, "kvm:kvm_pio")) { - ioport_event_get_key(evsel, sample, key); - return true; - } - - return false; -} - -static bool ioport_event_end(struct perf_evsel *evsel, - struct perf_sample *sample __maybe_unused, - struct event_key *key __maybe_unused) -{ - return kvm_entry_event(evsel); -} - -static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, - struct event_key *key, - char *decode) -{ - scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", (unsigned long long)key->key, - key->info ? "POUT" : "PIN"); -} - -static struct kvm_events_ops ioport_events = { - .is_begin_event = ioport_event_begin, - .is_end_event = ioport_event_end, - .decode_key = ioport_event_decode_key, - .name = "IO Port Access" -}; - static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) { - bool ret = true; + struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops; - if (!strcmp(kvm->report_event, "vmexit")) - kvm->events_ops = &exit_events; - else if (!strcmp(kvm->report_event, "mmio")) - kvm->events_ops = &mmio_events; - else if (!strcmp(kvm->report_event, "ioport")) - kvm->events_ops = &ioport_events; - else { - pr_err("Unknown report event:%s\n", kvm->report_event); - ret = false; + for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) { + if (!strcmp(events_ops->name, kvm->report_event)) { + kvm->events_ops = events_ops->ops; + return true; + } } - return ret; + return false; } struct vcpu_event_record { @@ -833,20 +620,6 @@ static int process_sample_event(struct perf_tool *tool, return 0; } -static int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) -{ - if (strstr(cpuid, "Intel")) { - kvm->exit_reasons = vmx_exit_reasons; - kvm->exit_reasons_isa = "VMX"; - } else if (strstr(cpuid, "AMD")) { - kvm->exit_reasons = svm_exit_reasons; - kvm->exit_reasons_isa = "SVM"; - } else - return -ENOTSUP; - - return 0; -} - static int cpu_isa_config(struct perf_kvm_stat *kvm) { char buf[64], *cpuid; @@ -1305,13 +1078,6 @@ exit: return ret; } -static const char * const kvm_events_tp[] = { - "kvm:kvm_entry", - "kvm:kvm_exit", - "kvm:kvm_mmio", - "kvm:kvm_pio", -}; - #define STRDUP_FAIL_EXIT(s) \ ({ char *_p; \ _p = strdup(s); \ @@ -1323,7 +1089,7 @@ static const char * const kvm_events_tp[] = { static int kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) { - unsigned int rec_argc, i, j; + unsigned int rec_argc, i, j, events_tp_size; const char **rec_argv; const char * const record_args[] = { "record", @@ -1331,9 +1097,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) "-m", "1024", "-c", "1", }; + const char * const *events_tp; + events_tp_size = 0; + + for (events_tp = kvm_events_tp; *events_tp; events_tp++) + events_tp_size++; rec_argc = ARRAY_SIZE(record_args) + argc + 2 + - 2 * ARRAY_SIZE(kvm_events_tp); + 2 * events_tp_size; rec_argv = calloc(rec_argc + 1, sizeof(char *)); if (rec_argv == NULL) @@ -1342,7 +1113,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) for (i = 0; i < ARRAY_SIZE(record_args); i++) rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); - for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { + for (j = 0; j < events_tp_size; j++) { rec_argv[i++] = "-e"; rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); } @@ -1396,16 +1167,16 @@ static struct perf_evlist *kvm_live_event_list(void) { struct perf_evlist *evlist; char *tp, *name, *sys; - unsigned int j; int err = -1; + const char * const *events_tp; evlist = perf_evlist__new(); if (evlist == NULL) return NULL; - for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) { + for (events_tp = kvm_events_tp; *events_tp; events_tp++) { - tp = strdup(kvm_events_tp[j]); + tp = strdup(*events_tp); if (tp == NULL) goto out; @@ -1414,7 +1185,7 @@ static struct perf_evlist *kvm_live_event_list(void) name = strchr(tp, ':'); if (name == NULL) { pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n", - kvm_events_tp[j]); + *events_tp); free(tp); goto out; } @@ -1422,7 +1193,7 @@ static struct perf_evlist *kvm_live_event_list(void) name++; if (perf_evlist__add_newtp(evlist, sys, name, NULL)) { - pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]); + pr_err("Failed to add %s tracepoint to the list\n", *events_tp); free(tp); goto out; } diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h new file mode 100644 index 000000000000..d0d9fb1ae52a --- /dev/null +++ b/tools/perf/util/kvm-stat.h @@ -0,0 +1,130 @@ +#ifndef __PERF_KVM_STAT_H +#define __PERF_KVM_STAT_H + +#include "../perf.h" +#include "evsel.h" +#include "evlist.h" +#include "session.h" +#include "tool.h" +#include "stat.h" + +struct event_key { + #define INVALID_KEY (~0ULL) + u64 key; + int info; +}; + +struct kvm_event_stats { + u64 time; + struct stats stats; +}; + +struct kvm_event { + struct list_head hash_entry; + struct rb_node rb; + + struct event_key key; + + struct kvm_event_stats total; + + #define DEFAULT_VCPU_NUM 8 + int max_vcpu; + struct kvm_event_stats *vcpu; +}; + +typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); + +struct kvm_event_key { + const char *name; + key_cmp_fun key; +}; + +struct perf_kvm_stat; + +struct kvm_events_ops { + bool (*is_begin_event)(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key); + bool (*is_end_event)(struct perf_evsel *evsel, + struct perf_sample *sample, struct event_key *key); + void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, + char *decode); + const char *name; +}; + +struct exit_reasons_table { + unsigned long exit_code; + const char *reason; +}; + +#define EVENTS_BITS 12 +#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) + +struct perf_kvm_stat { + struct perf_tool tool; + struct record_opts opts; + struct perf_evlist *evlist; + struct perf_session *session; + + const char *file_name; + const char *report_event; + const char *sort_key; + int trace_vcpu; + + struct exit_reasons_table *exit_reasons; + const char *exit_reasons_isa; + + struct kvm_events_ops *events_ops; + key_cmp_fun compare; + struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; + + u64 total_time; + u64 total_count; + u64 lost_events; + u64 duration; + + const char *pid_str; + struct intlist *pid_list; + + struct rb_root result; + + int timerfd; + unsigned int display_time; + bool live; +}; + +struct kvm_reg_events_ops { + const char *name; + struct kvm_events_ops *ops; +}; + +void exit_event_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key); +bool exit_event_begin(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key); +bool exit_event_end(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key); +void exit_event_decode_key(struct perf_kvm_stat *kvm, + struct event_key *key, + char *decode); + +bool kvm_exit_event(struct perf_evsel *evsel); +bool kvm_entry_event(struct perf_evsel *evsel); + +#define define_exit_reasons_table(name, symbols) \ + static struct exit_reasons_table name[] = { \ + symbols, { -1, NULL } \ + } + +/* + * arch specific callbacks and data structures + */ +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid); + +extern const char * const kvm_events_tp[]; +extern struct kvm_reg_events_ops kvm_reg_events_ops[]; + +#endif /* __PERF_KVM_STAT_H */ From 54c801ff71ba9c9ae41871e226b9d846ff9c6bab Mon Sep 17 00:00:00 2001 From: Alexander Yarygin Date: Thu, 3 Jul 2014 18:29:06 +0400 Subject: [PATCH 03/33] perf kvm: Add skip_event() for --duration option Current code skips output of the x86 specific HLT event in order to avoid flooding the output with enabled --duration option. The events to be skipped should be architecture dependent, though. Let's add an architecture specific array of events to be skipped and introduce a skip_event() function checking against that array. Reviewed-by: Christian Borntraeger Reviewed-by: Cornelia Huck Reviewed-by: David Ahern Signed-off-by: Alexander Yarygin Cc: Christian Borntraeger Cc: Cornelia Huck Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1404397747-20939-4-git-send-email-yarygin@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/kvm-stat.c | 5 +++++ tools/perf/builtin-kvm.c | 13 ++++++++++++- tools/perf/util/kvm-stat.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c index 2f8d2c1af5ca..14e4e668fad7 100644 --- a/tools/perf/arch/x86/util/kvm-stat.c +++ b/tools/perf/arch/x86/util/kvm-stat.c @@ -136,6 +136,11 @@ struct kvm_reg_events_ops kvm_reg_events_ops[] = { { NULL, NULL }, }; +const char * const kvm_skip_events[] = { + "HLT", + NULL, +}; + int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) { if (strstr(cpuid, "Intel")) { diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 75ee8c1a6baf..fc2d63d3e791 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -261,6 +261,17 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, return true; } +static bool skip_event(const char *event) +{ + const char * const *skip_events; + + for (skip_events = kvm_skip_events; *skip_events; skip_events++) + if (!strcmp(event, *skip_events)) + return true; + + return false; +} + static bool handle_end_event(struct perf_kvm_stat *kvm, struct vcpu_event_record *vcpu_record, struct event_key *key, @@ -312,7 +323,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, char decode[DECODE_STR_LEN]; kvm->events_ops->decode_key(kvm, &event->key, decode); - if (strcmp(decode, "HLT")) { + if (!skip_event(decode)) { pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n", sample->time, sample->pid, vcpu_record->vcpu_id, decode, time_diff/1000); diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index d0d9fb1ae52a..ba937caa28ac 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -126,5 +126,6 @@ int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid); extern const char * const kvm_events_tp[]; extern struct kvm_reg_events_ops kvm_reg_events_ops[]; +extern const char * const kvm_skip_events[]; #endif /* __PERF_KVM_STAT_H */ From 3be8e2a0a53c3179a44a933614f6a893da0b5c19 Mon Sep 17 00:00:00 2001 From: Alexander Yarygin Date: Thu, 3 Jul 2014 18:29:07 +0400 Subject: [PATCH 04/33] perf kvm: Add stat support on s390 On s390, the vmexit event has a tree-like structure: between exit_event_begin and exit_event_end several other events may happen and with each of them refining the previous ones. This patch adds a decoder for such events to the generic code and also the files and kvm-stat.c for s390. Commands 'perf kvm stat record', 'report' and 'live' are supported. Reviewed-by: David Ahern Signed-off-by: Alexander Yarygin Acked-by: Christian Borntraeger Cc: Christian Borntraeger Cc: Cornelia Huck Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1404397747-20939-5-git-send-email-yarygin@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/s390/include/uapi/asm/Kbuild | 1 + arch/s390/include/uapi/asm/kvm_perf.h | 25 ++++++ tools/perf/Documentation/perf-kvm.txt | 16 ++-- tools/perf/MANIFEST | 2 + tools/perf/arch/s390/Makefile | 2 + tools/perf/arch/s390/util/kvm-stat.c | 105 ++++++++++++++++++++++++++ tools/perf/builtin-kvm.c | 52 ++++++++++++- tools/perf/util/kvm-stat.h | 9 +++ 8 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 arch/s390/include/uapi/asm/kvm_perf.h create mode 100644 tools/perf/arch/s390/util/kvm-stat.c diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild index 6a9a9eb645f5..0e2b54db82bc 100644 --- a/arch/s390/include/uapi/asm/Kbuild +++ b/arch/s390/include/uapi/asm/Kbuild @@ -16,6 +16,7 @@ header-y += ioctls.h header-y += ipcbuf.h header-y += kvm.h header-y += kvm_para.h +header-y += kvm_perf.h header-y += kvm_virtio.h header-y += mman.h header-y += monwriter.h diff --git a/arch/s390/include/uapi/asm/kvm_perf.h b/arch/s390/include/uapi/asm/kvm_perf.h new file mode 100644 index 000000000000..397282727e21 --- /dev/null +++ b/arch/s390/include/uapi/asm/kvm_perf.h @@ -0,0 +1,25 @@ +/* + * Definitions for perf-kvm on s390 + * + * Copyright 2014 IBM Corp. + * Author(s): Alexander Yarygin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#ifndef __LINUX_KVM_PERF_S390_H +#define __LINUX_KVM_PERF_S390_H + +#include + +#define DECODE_STR_LEN 40 + +#define VCPU_ID "id" + +#define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" +#define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" +#define KVM_EXIT_REASON "icptcode" + +#endif diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 52276a6d2b75..6e689dc89a2f 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt @@ -51,9 +51,9 @@ There are a couple of variants of perf kvm: 'perf kvm stat ' to run a command and gather performance counter statistics. Especially, perf 'kvm stat record/report' generates a statistical analysis - of KVM events. Currently, vmexit, mmio and ioport events are supported. - 'perf kvm stat record ' records kvm events and the events between - start and end . + of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only) + events are supported. 'perf kvm stat record ' records kvm events + and the events between start and end . And this command produces a file which contains tracing results of kvm events. @@ -103,8 +103,8 @@ STAT REPORT OPTIONS analyze events which occures on this vcpu. (default: all vcpus) --event=:: - event to be analyzed. Possible values: vmexit, mmio, ioport. - (default: vmexit) + event to be analyzed. Possible values: vmexit, mmio (x86 only), + ioport (x86 only). (default: vmexit) -k:: --key=:: Sorting key. Possible values: sample (default, sort by samples @@ -138,7 +138,8 @@ STAT LIVE OPTIONS --event=:: - event to be analyzed. Possible values: vmexit, mmio, ioport. + event to be analyzed. Possible values: vmexit, + mmio (x86 only), ioport (x86 only). (default: vmexit) -k:: @@ -147,7 +148,8 @@ STAT LIVE OPTIONS number), time (sort by average time). --duration=:: - Show events other than HLT that take longer than duration usecs. + Show events other than HLT (x86 only) or Wait state (s390 only) + that take longer than duration usecs. SEE ALSO -------- diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 02b485d619cd..344c4d3d0a4a 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -38,3 +38,5 @@ arch/x86/include/uapi/asm/svm.h arch/x86/include/uapi/asm/vmx.h arch/x86/include/uapi/asm/kvm.h arch/x86/include/uapi/asm/kvm_perf.h +arch/s390/include/uapi/asm/sie.h +arch/s390/include/uapi/asm/kvm_perf.h diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile index 744e629797be..798ac7379c5f 100644 --- a/tools/perf/arch/s390/Makefile +++ b/tools/perf/arch/s390/Makefile @@ -3,3 +3,5 @@ PERF_HAVE_DWARF_REGS := 1 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o endif LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o +HAVE_KVM_STAT_SUPPORT := 1 +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c new file mode 100644 index 000000000000..a5dbc07ec9dc --- /dev/null +++ b/tools/perf/arch/s390/util/kvm-stat.c @@ -0,0 +1,105 @@ +/* + * Arch specific functions for perf kvm stat. + * + * Copyright 2014 IBM Corp. + * Author(s): Alexander Yarygin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#include "../../util/kvm-stat.h" +#include + +define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); +define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); +define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes); +define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); +define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); + +static void event_icpt_insn_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + unsigned long insn; + + insn = perf_evsel__intval(evsel, sample, "instruction"); + key->key = icpt_insn_decoder(insn); + key->exit_reasons = sie_icpt_insn_codes; +} + +static void event_sigp_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + key->key = perf_evsel__intval(evsel, sample, "order_code"); + key->exit_reasons = sie_sigp_order_codes; +} + +static void event_diag_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + key->key = perf_evsel__intval(evsel, sample, "code"); + key->exit_reasons = sie_diagnose_codes; +} + +static void event_icpt_prog_get_key(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + key->key = perf_evsel__intval(evsel, sample, "code"); + key->exit_reasons = sie_icpt_prog_codes; +} + +static struct child_event_ops child_events[] = { + { .name = "kvm:kvm_s390_intercept_instruction", + .get_key = event_icpt_insn_get_key }, + { .name = "kvm:kvm_s390_handle_sigp", + .get_key = event_sigp_get_key }, + { .name = "kvm:kvm_s390_handle_diag", + .get_key = event_diag_get_key }, + { .name = "kvm:kvm_s390_intercept_prog", + .get_key = event_icpt_prog_get_key }, + { NULL, NULL }, +}; + +static struct kvm_events_ops exit_events = { + .is_begin_event = exit_event_begin, + .is_end_event = exit_event_end, + .child_ops = child_events, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + +const char * const kvm_events_tp[] = { + "kvm:kvm_s390_sie_enter", + "kvm:kvm_s390_sie_exit", + "kvm:kvm_s390_intercept_instruction", + "kvm:kvm_s390_handle_sigp", + "kvm:kvm_s390_handle_diag", + "kvm:kvm_s390_intercept_prog", + NULL, +}; + +struct kvm_reg_events_ops kvm_reg_events_ops[] = { + { .name = "vmexit", .ops = &exit_events }, + { NULL, NULL }, +}; + +const char * const kvm_skip_events[] = { + "Wait state", + NULL, +}; + +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) +{ + if (strstr(cpuid, "IBM/S390")) { + kvm->exit_reasons = sie_exit_reasons; + kvm->exit_reasons_isa = "SIE"; + } else + return -ENOTSUP; + + return 0; +} diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index fc2d63d3e791..43367eb00510 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -88,7 +88,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, char *decode) { - const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons, + const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, key->key); scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); @@ -261,6 +261,43 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, return true; } +static bool is_child_event(struct perf_kvm_stat *kvm, + struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key) +{ + struct child_event_ops *child_ops; + + child_ops = kvm->events_ops->child_ops; + + if (!child_ops) + return false; + + for (; child_ops->name; child_ops++) { + if (!strcmp(evsel->name, child_ops->name)) { + child_ops->get_key(evsel, sample, key); + return true; + } + } + + return false; +} + +static bool handle_child_event(struct perf_kvm_stat *kvm, + struct vcpu_event_record *vcpu_record, + struct event_key *key, + struct perf_sample *sample __maybe_unused) +{ + struct kvm_event *event = NULL; + + if (key->key != INVALID_KEY) + event = find_create_kvm_event(kvm, key); + + vcpu_record->last_event = event; + + return true; +} + static bool skip_event(const char *event) { const char * const *skip_events; @@ -361,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, struct perf_sample *sample) { struct vcpu_event_record *vcpu_record; - struct event_key key = {.key = INVALID_KEY}; + struct event_key key = { .key = INVALID_KEY, + .exit_reasons = kvm->exit_reasons }; vcpu_record = per_vcpu_record(thread, evsel, sample); if (!vcpu_record) @@ -375,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, if (kvm->events_ops->is_begin_event(evsel, sample, &key)) return handle_begin_event(kvm, vcpu_record, &key, sample->time); + if (is_child_event(kvm, evsel, sample, &key)) + return handle_child_event(kvm, vcpu_record, &key, sample); + if (kvm->events_ops->is_end_event(evsel, sample, &key)) return handle_end_event(kvm, vcpu_record, &key, sample); @@ -1143,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) { const struct option kvm_events_report_options[] = { OPT_STRING(0, "event", &kvm->report_event, "report event", - "event for reporting: vmexit, mmio, ioport"), + "event for reporting: vmexit, " + "mmio (x86 only), ioport (x86 only)"), OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, "vcpu id to report"), OPT_STRING('k', "key", &kvm->sort_key, "sort-key", @@ -1249,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, "key for sorting: sample(sort by samples number)" " time (sort by avg time)"), OPT_U64(0, "duration", &kvm->duration, - "show events other than HALT that take longer than duration usecs"), + "show events other than" + " HLT (x86 only) or Wait state (s390 only)" + " that take longer than duration usecs"), OPT_END() }; const char * const live_usage[] = { diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index ba937caa28ac..0b5a8cd2ee79 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -12,6 +12,7 @@ struct event_key { #define INVALID_KEY (~0ULL) u64 key; int info; + struct exit_reasons_table *exit_reasons; }; struct kvm_event_stats { @@ -41,12 +42,20 @@ struct kvm_event_key { struct perf_kvm_stat; +struct child_event_ops { + void (*get_key)(struct perf_evsel *evsel, + struct perf_sample *sample, + struct event_key *key); + const char *name; +}; + struct kvm_events_ops { bool (*is_begin_event)(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key); bool (*is_end_event)(struct perf_evsel *evsel, struct perf_sample *sample, struct event_key *key); + struct child_event_ops *child_ops; void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, char *decode); const char *name; From 05f832e3a267d6e45d092595bdf9339d127ea137 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 9 Jul 2014 16:16:31 +0200 Subject: [PATCH 05/33] perf script: Add missing calls to Py_DECREF for return values Signed-off-by: Joseph Schuchart Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Ilsche Link: http://lkml.kernel.org/r/53BD4EBF.5050407@tu-dresden.de Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/scripting-engines/trace-event-python.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index e55b65a65558..b6c1a69f2b18 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -50,10 +50,14 @@ static int zero_flag_atom; static PyObject *main_module, *main_dict; +static void handler_call_die(const char *handler_name) NORETURN; static void handler_call_die(const char *handler_name) { PyErr_Print(); Py_FatalError("problem in Python trace event handler"); + // Py_FatalError does not return + // but we have to make the compiler happy + abort(); } /* @@ -97,6 +101,7 @@ static void define_value(enum print_arg_type field_type, retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die(handler_name); + Py_DECREF(retval); } Py_DECREF(t); @@ -143,6 +148,7 @@ static void define_field(enum print_arg_type field_type, retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die(handler_name); + Py_DECREF(retval); } Py_DECREF(t); @@ -361,6 +367,7 @@ static void python_process_tracepoint(struct perf_sample *sample, retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die(handler_name); + Py_DECREF(retval); } else { handler = PyDict_GetItemString(main_dict, "trace_unhandled"); if (handler && PyCallable_Check(handler)) { @@ -368,6 +375,7 @@ static void python_process_tracepoint(struct perf_sample *sample, retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die("trace_unhandled"); + Py_DECREF(retval); } Py_DECREF(dict); } @@ -427,6 +435,7 @@ static void python_process_general_event(struct perf_sample *sample, retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die(handler_name); + Py_DECREF(retval); exit: Py_DECREF(dict); Py_DECREF(t); @@ -548,8 +557,7 @@ static int python_stop_script(void) retval = PyObject_CallObject(handler, NULL); if (retval == NULL) handler_call_die("trace_end"); - else - Py_DECREF(retval); + Py_DECREF(retval); out: Py_XDECREF(main_dict); Py_XDECREF(main_module); From 0f5f5bcd112292f14b75750dde7461463bb1c7bb Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Thu, 10 Jul 2014 13:50:51 +0200 Subject: [PATCH 06/33] perf script: Add callchain to generic and tracepoint events This provides valuable information for tracing performance problems. Since this change alters the interface for the python scripts, also adjust the script generation and the provided scripts. Signed-off-by: Joseph Schuchart Acked-by: Thomas Ilsche Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Ilsche Link: http://lkml.kernel.org/r/53BE7E1B.10503@tu-dresden.de Signed-off-by: Arnaldo Carvalho de Melo --- .../Perf-Trace-Util/lib/Perf/Trace/Core.py | 3 +- tools/perf/scripts/python/check-perf-trace.py | 4 +- .../scripts/python/failed-syscalls-by-pid.py | 2 +- tools/perf/scripts/python/futex-contention.py | 4 +- tools/perf/scripts/python/net_dropmonitor.py | 2 +- tools/perf/scripts/python/netdev-times.py | 26 ++--- tools/perf/scripts/python/sched-migration.py | 41 ++++--- tools/perf/scripts/python/sctop.py | 2 +- .../scripts/python/syscall-counts-by-pid.py | 2 +- tools/perf/scripts/python/syscall-counts.py | 2 +- .../scripting-engines/trace-event-python.c | 106 +++++++++++++++++- 11 files changed, 146 insertions(+), 48 deletions(-) diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py index de7211e4fa47..38dfb720fb6f 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py @@ -107,12 +107,13 @@ def taskState(state): class EventHeaders: def __init__(self, common_cpu, common_secs, common_nsecs, - common_pid, common_comm): + common_pid, common_comm, common_callchain): self.cpu = common_cpu self.secs = common_secs self.nsecs = common_nsecs self.pid = common_pid self.comm = common_comm + self.callchain = common_callchain def ts(self): return (self.secs * (10 ** 9)) + self.nsecs diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py index 4647a7694cf6..334599c6032c 100644 --- a/tools/perf/scripts/python/check-perf-trace.py +++ b/tools/perf/scripts/python/check-perf-trace.py @@ -27,7 +27,7 @@ def trace_end(): def irq__softirq_entry(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - vec): + common_callchain, vec): print_header(event_name, common_cpu, common_secs, common_nsecs, common_pid, common_comm) @@ -38,7 +38,7 @@ def irq__softirq_entry(event_name, context, common_cpu, def kmem__kmalloc(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - call_site, ptr, bytes_req, bytes_alloc, + common_callchain, call_site, ptr, bytes_req, bytes_alloc, gfp_flags): print_header(event_name, common_cpu, common_secs, common_nsecs, common_pid, common_comm) diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py index 266a8364bce5..cafeff3d74db 100644 --- a/tools/perf/scripts/python/failed-syscalls-by-pid.py +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py @@ -39,7 +39,7 @@ def trace_end(): def raw_syscalls__sys_exit(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - id, ret): + common_callchain, id, ret): if (for_comm and common_comm != for_comm) or \ (for_pid and common_pid != for_pid ): return diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py index 11e70a388d41..0f5cf437b602 100644 --- a/tools/perf/scripts/python/futex-contention.py +++ b/tools/perf/scripts/python/futex-contention.py @@ -21,7 +21,7 @@ thread_blocktime = {} lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time process_names = {} # long-lived pid-to-execname mapping -def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, +def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, nr, uaddr, op, val, utime, uaddr2, val3): cmd = op & FUTEX_CMD_MASK if cmd != FUTEX_WAIT: @@ -31,7 +31,7 @@ def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, thread_thislock[tid] = uaddr thread_blocktime[tid] = nsecs(s, ns) -def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, +def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, nr, ret): if thread_blocktime.has_key(tid): elapsed = nsecs(s, ns) - thread_blocktime[tid] diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py index b5740599aabd..0b6ce8c253e8 100755 --- a/tools/perf/scripts/python/net_dropmonitor.py +++ b/tools/perf/scripts/python/net_dropmonitor.py @@ -66,7 +66,7 @@ def trace_end(): print_drop_table() # called from perf, when it finds a correspoinding event -def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, +def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, location, protocol): slocation = str(location) try: diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py index 9aa0a32972e8..4d21ef2d601d 100644 --- a/tools/perf/scripts/python/netdev-times.py +++ b/tools/perf/scripts/python/netdev-times.py @@ -224,75 +224,75 @@ def trace_end(): (len(rx_skb_list), of_count_rx_skb_list) # called from perf, when it finds a correspoinding event -def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): +def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": return event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) all_event_list.append(event_info) -def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): +def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec): if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": return event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) all_event_list.append(event_info) -def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): +def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec): if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": return event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) all_event_list.append(event_info) def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, - irq, irq_name): + callchain, irq, irq_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, irq_name) all_event_list.append(event_info) -def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): +def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) all_event_list.append(event_info) -def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): +def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, napi, dev_name) all_event_list.append(event_info) -def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, +def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, skblen, dev_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, skblen, dev_name) all_event_list.append(event_info) -def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, +def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, skblen, dev_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, skblen, dev_name) all_event_list.append(event_info) -def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, +def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, skblen, dev_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, skblen, dev_name) all_event_list.append(event_info) -def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, +def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, skblen, rc, dev_name): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, skblen, rc ,dev_name) all_event_list.append(event_info) -def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, +def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, protocol, location): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, protocol, location) all_event_list.append(event_info) -def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): +def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr) all_event_list.append(event_info) -def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, +def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, skblen): event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, skbaddr, skblen) diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py index 74d55ec08aed..de66cb3b72c9 100644 --- a/tools/perf/scripts/python/sched-migration.py +++ b/tools/perf/scripts/python/sched-migration.py @@ -369,93 +369,92 @@ def trace_end(): def sched__sched_stat_runtime(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, runtime, vruntime): + common_callchain, comm, pid, runtime, vruntime): pass def sched__sched_stat_iowait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, delay): + common_callchain, comm, pid, delay): pass def sched__sched_stat_sleep(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, delay): + common_callchain, comm, pid, delay): pass def sched__sched_stat_wait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, delay): + common_callchain, comm, pid, delay): pass def sched__sched_process_fork(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - parent_comm, parent_pid, child_comm, child_pid): + common_callchain, parent_comm, parent_pid, child_comm, child_pid): pass def sched__sched_process_wait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio): + common_callchain, comm, pid, prio): pass def sched__sched_process_exit(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio): + common_callchain, comm, pid, prio): pass def sched__sched_process_free(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio): + common_callchain, comm, pid, prio): pass def sched__sched_migrate_task(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio, orig_cpu, + common_callchain, comm, pid, prio, orig_cpu, dest_cpu): headers = EventHeaders(common_cpu, common_secs, common_nsecs, - common_pid, common_comm) + common_pid, common_comm, common_callchain) parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) def sched__sched_switch(event_name, context, common_cpu, - common_secs, common_nsecs, common_pid, common_comm, + common_secs, common_nsecs, common_pid, common_comm, common_callchain, prev_comm, prev_pid, prev_prio, prev_state, next_comm, next_pid, next_prio): headers = EventHeaders(common_cpu, common_secs, common_nsecs, - common_pid, common_comm) + common_pid, common_comm, common_callchain) parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, next_comm, next_pid, next_prio) def sched__sched_wakeup_new(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio, success, + common_callchain, comm, pid, prio, success, target_cpu): headers = EventHeaders(common_cpu, common_secs, common_nsecs, - common_pid, common_comm) + common_pid, common_comm, common_callchain) parser.wake_up(headers, comm, pid, success, target_cpu, 1) def sched__sched_wakeup(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio, success, + common_callchain, comm, pid, prio, success, target_cpu): headers = EventHeaders(common_cpu, common_secs, common_nsecs, - common_pid, common_comm) + common_pid, common_comm, common_callchain) parser.wake_up(headers, comm, pid, success, target_cpu, 0) def sched__sched_wait_task(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid, prio): + common_callchain, comm, pid, prio): pass def sched__sched_kthread_stop_ret(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - ret): + common_callchain, ret): pass def sched__sched_kthread_stop(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - comm, pid): + common_callchain, comm, pid): pass -def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, - common_pid, common_comm): +def trace_unhandled(event_name, context, event_fields_dict): pass diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py index c9f3058b7dd4..61621b93affb 100644 --- a/tools/perf/scripts/python/sctop.py +++ b/tools/perf/scripts/python/sctop.py @@ -44,7 +44,7 @@ def trace_begin(): def raw_syscalls__sys_enter(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - id, args): + common_callchain, id, args): if for_comm is not None: if common_comm != for_comm: return diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py index cf2054c529c9..daf314cc5dd3 100644 --- a/tools/perf/scripts/python/syscall-counts-by-pid.py +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py @@ -38,7 +38,7 @@ def trace_end(): def raw_syscalls__sys_enter(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - id, args): + common_callchain, id, args): if (for_comm and common_comm != for_comm) or \ (for_pid and common_pid != for_pid ): diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py index 92b29381bd39..e66a7730aeb5 100644 --- a/tools/perf/scripts/python/syscall-counts.py +++ b/tools/perf/scripts/python/syscall-counts.py @@ -35,7 +35,7 @@ def trace_end(): def raw_syscalls__sys_enter(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, - id, args): + common_callchain, id, args): if for_comm is not None: if common_comm != for_comm: return diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index b6c1a69f2b18..cf65404472cb 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -32,6 +32,7 @@ #include "../event.h" #include "../thread.h" #include "../trace-event.h" +#include "../machine.h" PyMODINIT_FUNC initperf_trace_context(void); @@ -278,12 +279,90 @@ static PyObject *get_field_numeric_entry(struct event_format *event, return obj; } + +static PyObject *python_process_callchain(struct perf_sample *sample, + struct perf_evsel *evsel, + struct addr_location *al) +{ + PyObject *pylist; + + pylist = PyList_New(0); + if (!pylist) + Py_FatalError("couldn't create Python list"); + + if (!symbol_conf.use_callchain || !sample->callchain) + goto exit; + + if (machine__resolve_callchain(al->machine, evsel, al->thread, + sample, NULL, NULL, + PERF_MAX_STACK_DEPTH) != 0) { + pr_err("Failed to resolve callchain. Skipping\n"); + goto exit; + } + callchain_cursor_commit(&callchain_cursor); + + + while (1) { + PyObject *pyelem; + struct callchain_cursor_node *node; + node = callchain_cursor_current(&callchain_cursor); + if (!node) + break; + + pyelem = PyDict_New(); + if (!pyelem) + Py_FatalError("couldn't create Python dictionary"); + + + pydict_set_item_string_decref(pyelem, "ip", + PyLong_FromUnsignedLongLong(node->ip)); + + if (node->sym) { + PyObject *pysym = PyDict_New(); + if (!pysym) + Py_FatalError("couldn't create Python dictionary"); + pydict_set_item_string_decref(pysym, "start", + PyLong_FromUnsignedLongLong(node->sym->start)); + pydict_set_item_string_decref(pysym, "end", + PyLong_FromUnsignedLongLong(node->sym->end)); + pydict_set_item_string_decref(pysym, "binding", + PyInt_FromLong(node->sym->binding)); + pydict_set_item_string_decref(pysym, "name", + PyString_FromStringAndSize(node->sym->name, + node->sym->namelen)); + pydict_set_item_string_decref(pyelem, "sym", pysym); + } + + if (node->map) { + struct map *map = node->map; + const char *dsoname = "[unknown]"; + if (map && map->dso && (map->dso->name || map->dso->long_name)) { + if (symbol_conf.show_kernel_path && map->dso->long_name) + dsoname = map->dso->long_name; + else if (map->dso->name) + dsoname = map->dso->name; + } + pydict_set_item_string_decref(pyelem, "dso", + PyString_FromString(dsoname)); + } + + callchain_cursor_advance(&callchain_cursor); + PyList_Append(pylist, pyelem); + Py_DECREF(pyelem); + } + +exit: + return pylist; +} + + static void python_process_tracepoint(struct perf_sample *sample, struct perf_evsel *evsel, struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; + PyObject *handler, *retval, *context, *t, *obj, *callchain; + PyObject *dict = NULL; static char handler_name[256]; struct format_field *field; unsigned long s, ns; @@ -326,18 +405,23 @@ static void python_process_tracepoint(struct perf_sample *sample, PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); PyTuple_SetItem(t, n++, context); + /* ip unwinding */ + callchain = python_process_callchain(sample, evsel, al); + if (handler) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); PyTuple_SetItem(t, n++, PyInt_FromLong(s)); PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); PyTuple_SetItem(t, n++, PyString_FromString(comm)); + PyTuple_SetItem(t, n++, callchain); } else { pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); + pydict_set_item_string_decref(dict, "common_callchain", callchain); } for (field = event->format.fields; field; field = field->next) { if (field->flags & FIELD_IS_STRING) { @@ -357,6 +441,7 @@ static void python_process_tracepoint(struct perf_sample *sample, pydict_set_item_string_decref(dict, field->name, obj); } + if (!handler) PyTuple_SetItem(t, n++, dict); @@ -388,7 +473,7 @@ static void python_process_general_event(struct perf_sample *sample, struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *t, *dict; + PyObject *handler, *retval, *t, *dict, *callchain; static char handler_name[64]; unsigned n = 0; @@ -428,6 +513,10 @@ static void python_process_general_event(struct perf_sample *sample, PyString_FromString(al->sym->name)); } + /* ip unwinding */ + callchain = python_process_callchain(sample, evsel, al); + pydict_set_item_string_decref(dict, "callchain", callchain); + PyTuple_SetItem(t, n++, dict); if (_PyTuple_Resize(&t, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -624,6 +713,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) fprintf(ofp, "common_nsecs, "); fprintf(ofp, "common_pid, "); fprintf(ofp, "common_comm,\n\t"); + fprintf(ofp, "common_callchain, "); not_first = 0; count = 0; @@ -667,7 +757,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) fprintf(ofp, "%%u"); } - fprintf(ofp, "\\n\" %% \\\n\t\t("); + fprintf(ofp, "\" %% \\\n\t\t("); not_first = 0; count = 0; @@ -703,7 +793,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) fprintf(ofp, "%s", f->name); } - fprintf(ofp, "),\n\n"); + fprintf(ofp, ")\n\n"); + + fprintf(ofp, "\t\tfor node in common_callchain:"); + fprintf(ofp, "\n\t\t\tif 'sym' in node:"); + fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); + fprintf(ofp, "\n\t\t\telse:"); + fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n"); + fprintf(ofp, "\t\tprint \"\\n\"\n\n"); + } fprintf(ofp, "def trace_unhandled(event_name, context, " From 57608cfd8827a74237d264a197722e2c99f72da4 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Thu, 10 Jul 2014 13:50:56 +0200 Subject: [PATCH 07/33] perf script: Provide additional sample information on generic events To python scripts, including pid, tid, and cpu for which the event was recorded. At the moment, the pointer to the sample struct is passed to scripts, which seems to be of little use. The patch puts this information in dictionaries for easy access by Python scripts. Signed-off-by: Joseph Schuchart Acked-by: Thomas Ilsche Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Ilsche Link: http://lkml.kernel.org/r/53BE7E20.8080500@tu-dresden.de Signed-off-by: Arnaldo Carvalho de Melo --- .../scripting-engines/trace-event-python.c | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cf65404472cb..b366b48646ca 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -473,7 +473,7 @@ static void python_process_general_event(struct perf_sample *sample, struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *t, *dict, *callchain; + PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; static char handler_name[64]; unsigned n = 0; @@ -489,6 +489,10 @@ static void python_process_general_event(struct perf_sample *sample, if (!dict) Py_FatalError("couldn't create Python dictionary"); + dict_sample = PyDict_New(); + if (!dict_sample) + Py_FatalError("couldn't create Python dictionary"); + snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); handler = PyDict_GetItemString(main_dict, handler_name); @@ -498,8 +502,21 @@ static void python_process_general_event(struct perf_sample *sample, pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( (const char *)&evsel->attr, sizeof(evsel->attr))); - pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( - (const char *)sample, sizeof(*sample))); + + pydict_set_item_string_decref(dict_sample, "pid", + PyInt_FromLong(sample->pid)); + pydict_set_item_string_decref(dict_sample, "tid", + PyInt_FromLong(sample->tid)); + pydict_set_item_string_decref(dict_sample, "cpu", + PyInt_FromLong(sample->cpu)); + pydict_set_item_string_decref(dict_sample, "ip", + PyLong_FromUnsignedLongLong(sample->ip)); + pydict_set_item_string_decref(dict_sample, "time", + PyLong_FromUnsignedLongLong(sample->time)); + pydict_set_item_string_decref(dict_sample, "period", + PyLong_FromUnsignedLongLong(sample->period)); + pydict_set_item_string_decref(dict, "sample", dict_sample); + pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( (const char *)sample->raw_data, sample->raw_size)); pydict_set_item_string_decref(dict, "comm", From 1fcb8768636d38cb6fdfeef83a5ee596c4bd9c56 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:25 +0300 Subject: [PATCH 08/33] perf machine: Fix the value used for unknown pids The value used for unknown pids cannot be zero because that is used by the "idle" task. Use -1 instead. Also handle the unknown pid case when creating map groups. Note that, threads with an unknown pid should not occur because fork (or synthesized) events precede the thread's existence. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 12 ++++++------ tools/perf/util/machine.c | 6 +++--- tools/perf/util/session.c | 5 +++-- tools/perf/util/thread.c | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index c38d06c04775..b7f555add0c8 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched, return -1; } - sched_out = machine__findnew_thread(machine, 0, prev_pid); - sched_in = machine__findnew_thread(machine, 0, next_pid); + sched_out = machine__findnew_thread(machine, -1, prev_pid); + sched_in = machine__findnew_thread(machine, -1, next_pid); out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); if (!out_events) { @@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched, { const u32 pid = perf_evsel__intval(evsel, sample, "pid"); const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); - struct thread *thread = machine__findnew_thread(machine, 0, pid); + struct thread *thread = machine__findnew_thread(machine, -1, pid); struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); u64 timestamp = sample->time; int cpu = sample->cpu; @@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched, struct thread *wakee; u64 timestamp = sample->time; - wakee = machine__findnew_thread(machine, 0, pid); + wakee = machine__findnew_thread(machine, -1, pid); atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); if (!atoms) { if (thread_atoms_insert(sched, wakee)) @@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, if (sched->profile_cpu == -1) return 0; - migrant = machine__findnew_thread(machine, 0, pid); + migrant = machine__findnew_thread(machine, -1, pid); atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); if (!atoms) { if (thread_atoms_insert(sched, migrant)) @@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, return -1; } - sched_in = machine__findnew_thread(machine, 0, next_pid); + sched_in = machine__findnew_thread(machine, -1, next_pid); sched->curr_thread[this_cpu] = sched_in; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e9b943acaa5e..5b8087728f28 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) return -ENOMEM; if (pid != HOST_KERNEL_ID) { - struct thread *thread = machine__findnew_thread(machine, 0, + struct thread *thread = machine__findnew_thread(machine, -1, pid); char comm[64]; @@ -286,7 +286,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, * the full rbtree: */ if (machine->last_match && machine->last_match->tid == tid) { - if (pid && pid != machine->last_match->pid_) + if (pid != -1 && pid != machine->last_match->pid_) machine->last_match->pid_ = pid; return machine->last_match; } @@ -297,7 +297,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, if (th->tid == tid) { machine->last_match = th; - if (pid && pid != th->pid_) + if (pid != -1 && pid != th->pid_) th->pid_ = pid; return th; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 64a186edc7be..c2f4ca917469 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr) struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) { - return machine__findnew_thread(&session->machines.host, 0, pid); + return machine__findnew_thread(&session->machines.host, -1, pid); } static struct thread *perf_session__register_idle_thread(struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, 0); + struct thread *thread; + thread = machine__findnew_thread(&session->machines.host, 0, 0); if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { pr_err("problem inserting idle task.\n"); thread = NULL; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2fde0d5e40b5..7a32f447a8e7 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine) struct thread *leader; pid_t pid = thread->pid_; - if (pid == thread->tid) { + if (pid == thread->tid || pid == -1) { thread->mg = map_groups__new(); } else { leader = machine__findnew_thread(machine, pid, pid); From 022c50d09c2c2bc31506ad16c4bcba7fb418ce34 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:27 +0300 Subject: [PATCH 09/33] perf script: Display PERF_RECORD_MISC_COMM_EXEC flag Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 9 ++++++++- tools/perf/util/evsel.c | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index d0281bdfa582..198c4cc313a1 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) { - return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); + const char *s; + + if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC) + s = " exec"; + else + s = ""; + + return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid); } int perf_event__process_comm(struct perf_tool *tool __maybe_unused, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8606175fe1e8..b760d32aae06 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -960,6 +960,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret += PRINT_ATTR2(exclude_user, exclude_kernel); ret += PRINT_ATTR2(exclude_hv, exclude_idle); ret += PRINT_ATTR2(mmap, comm); + ret += PRINT_ATTR2(mmap2, comm_exec); ret += PRINT_ATTR2(freq, inherit_stat); ret += PRINT_ATTR2(enable_on_exec, task); ret += PRINT_ATTR2(watermark, precise_ip); @@ -967,7 +968,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret += PRINT_ATTR2(exclude_host, exclude_guest); ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, "excl.callchain_user", exclude_callchain_user); - ret += PRINT_ATTR_U32(mmap2); ret += PRINT_ATTR_U32(wakeup_events); ret += PRINT_ATTR_U32(wakeup_watermark); @@ -1940,6 +1940,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, if_print(mmap); if_print(mmap2); if_print(comm); + if_print(comm_exec); if_print(freq); if_print(inherit_stat); if_print(enable_on_exec); From 39e09d40bea440d9cfe645b55aff251294318669 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:28 +0300 Subject: [PATCH 10/33] perf record: Select comm_exec flag if supported The comm_exec flag on the attribute can later be found in the perf.data file allowing a tool to know in advance if the captured data has the flag. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/record.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 049e0a09ccd3..165723152cfb 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel) evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; } +static void perf_probe_comm_exec(struct perf_evsel *evsel) +{ + evsel->attr.comm_exec = 1; +} + bool perf_can_sample_identifier(void) { return perf_probe_api(perf_probe_sample_identifier); } +static bool perf_can_comm_exec(void) +{ + return perf_probe_api(perf_probe_comm_exec); +} + void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) { struct perf_evsel *evsel; bool use_sample_identifier = false; + bool use_comm_exec; /* * Set the evsel leader links before we configure attributes, @@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) if (evlist->cpus->map[0] < 0) opts->no_inherit = true; - evlist__for_each(evlist, evsel) + use_comm_exec = perf_can_comm_exec(); + + evlist__for_each(evlist, evsel) { perf_evsel__config(evsel, opts); + if (!evsel->idx && use_comm_exec) + evsel->attr.comm_exec = 1; + } if (evlist->nr_entries > 1) { struct perf_evsel *first = perf_evlist__first(evlist); From 1f2a7069b6e895487b1d9229f5f62799cc4ea0aa Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:31 +0300 Subject: [PATCH 11/33] perf tools: Fix missing kernel map load thread__find_addr_map() falls back to trying the kernel maps if the address is negative and is not found in userspace maps. As commented in the code, the kernel maps must be "loaded" before use. This patch ensures that happens under the fallback condition also. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 198c4cc313a1..7e0e8ae568ec 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -788,6 +788,7 @@ try_again: cpumode == PERF_RECORD_MISC_USER && machine && mg != &machine->kmaps) { mg = &machine->kmaps; + load_map = true; goto try_again; } } else { From a2f3b6bf0adadcb5f9383c60aa1355e0f9cba3da Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:33 +0300 Subject: [PATCH 12/33] perf symbols: Fix missing GNU IFUNC symbols Symbols of type STT_GNU_IFUNC are functions so accept them as such. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-10-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6864661a79dd..dce5ccf61f11 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym) static inline int elf_sym__is_function(const GElf_Sym *sym) { - return elf_sym__type(sym) == STT_FUNC && + return (elf_sym__type(sym) == STT_FUNC || + elf_sym__type(sym) == STT_GNU_IFUNC) && sym->st_name != 0 && sym->st_shndx != SHN_UNDEF; } From e38b43c3f3fd8ebe6f558400d1647a923bc19d44 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:34 +0300 Subject: [PATCH 13/33] perf inject: Fix build id injection Build Ids won't be injected unless the build id feature flag is set. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-11-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 16c7c11ad06e..cf6a605a13e8 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject) ret = perf_session__process_events(session, &inject->tool); if (!file_out->is_pipe) { + if (inject->build_ids) + perf_header__set_feat(&session->header, + HEADER_BUILD_ID); session->header.data_size = inject->bytes_written; perf_session__write_header(session, session->evlist, file_out->fd, true); } From 4d40b051b1ac41ecbc818deed27750b4c1697520 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:35 +0300 Subject: [PATCH 14/33] perf callchain: Fix appending a callchain from a previous sample hist_entry__append_callchain() must check if the sample has a callcahin or it will append the callchain from a previous sample. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-12-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/callchain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 48b6d3f50012..437ee09727e6 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) { - if (!symbol_conf.use_callchain) + if (!symbol_conf.use_callchain || sample->callchain == NULL) return 0; return callchain_append(he->callchain, &callchain_cursor, sample->period); } From 5173fbb8a11b2857aeec9e5f4e9568d4e1b84dbd Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:38 +0300 Subject: [PATCH 15/33] perf buildid-cache: Apply force option to copying kcore Currently a copy of kcore is not made if there is one already with the same modules at the same addresses. Change this to make a copy anyway if the force (-f) option is also used. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-15-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-cache.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index b22dbb16f877..2a2c78f80876 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, return ret; } -static int build_id_cache__add_kcore(const char *filename, const char *debugdir) +static int build_id_cache__add_kcore(const char *filename, const char *debugdir, + bool force) { char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1]; char from_dir[PATH_MAX], to_dir[PATH_MAX]; @@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir) scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", debugdir, sbuildid); - if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { + if (!force && + !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { pr_debug("same kcore found in %s\n", to_dir); return 0; } @@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv, } if (kcore_filename && - build_id_cache__add_kcore(kcore_filename, debugdir)) + build_id_cache__add_kcore(kcore_filename, debugdir, force)) pr_warning("Couldn't add %s\n", kcore_filename); return ret; From c6d8f2a4a0c5e366330a6a2a94c06b652f4ca554 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:41 +0300 Subject: [PATCH 16/33] perf symbols: Record whether a dso is 64-bit Add a flag to 'struct dso' to record if the dso is 64-bit or not. Update the flag when reading the ELF. This is needed for instruction decoding. For example, x86 instruction decoding depends on whether or not the 64-bit instruction set is used. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-18-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 1 + tools/perf/util/dso.h | 1 + tools/perf/util/symbol-elf.c | 3 +++ tools/perf/util/symbol-minimal.c | 22 ++++++++++++++++++++++ tools/perf/util/symbol.c | 1 + tools/perf/util/symbol.h | 1 + 6 files changed, 29 insertions(+) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 819f10414f08..fc006fed8877 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -703,6 +703,7 @@ struct dso *dso__new(const char *name) dso->data.fd = -1; dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; + dso->is_64_bit = (sizeof(void *) == 8); dso->loaded = 0; dso->rel = 0; dso->sorted_by_name = 0; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ad553ba257bf..c239e86541a3 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -90,6 +90,7 @@ struct dso { u8 annotate_warned:1; u8 short_name_allocated:1; u8 long_name_allocated:1; + u8 is_64_bit:1; u8 sorted_by_name; u8 loaded; u8 rel; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index dce5ccf61f11..cef8f426356e 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -599,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, goto out_elf_end; } + ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64); + ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", NULL); if (ss->symshdr.sh_type != SHT_SYMTAB) @@ -699,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map, bool remap_kernel = false, adjust_kernel_syms = false; dso->symtab_type = syms_ss->type; + dso->is_64_bit = syms_ss->is_64_bit; dso->rel = syms_ss->ehdr.e_type == ET_REL; /* diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index bd15f490d04f..101f55d407d0 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused, return 0; } +static int fd__is_64_bit(int fd) +{ + u8 e_ident[EI_NIDENT]; + + if (lseek(fd, 0, SEEK_SET)) + return -1; + + if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) + return -1; + + if (memcmp(e_ident, ELFMAG, SELFMAG) || + e_ident[EI_VERSION] != EV_CURRENT) + return -1; + + return e_ident[EI_CLASS] == ELFCLASS64; +} + int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused, @@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, int kmodule __maybe_unused) { unsigned char *build_id[BUILD_ID_SIZE]; + int ret; + + ret = fd__is_64_bit(ss->fd); + if (ret >= 0) + dso->is_64_bit = ret; if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { dso__set_build_id(dso, build_id); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 2e6a2e219eb9..ae2e4464afa7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1065,6 +1065,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, &is_64_bit); if (err) goto out_err; + dso->is_64_bit = is_64_bit; if (list_empty(&md.maps)) { err = -EINVAL; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index a81877b1dee0..436169dd1d84 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -216,6 +216,7 @@ struct symsrc { GElf_Shdr dynshdr; bool adjust_symbols; + bool is_64_bit; #endif }; From bdac0bcf779250e89b96d4a3f381ebaf02c2f4a9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:43 +0300 Subject: [PATCH 17/33] perf symbols: Do not attempt to read data from kallsyms Record kallsyms binary type so that tools will not attempt to read binary data from it. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-20-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ae2e4464afa7..156ae36dfcfc 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1664,6 +1664,7 @@ do_kallsyms: free(kallsyms_allocated_filename); if (err > 0 && !dso__is_kcore(dso)) { + dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; dso__set_long_name(dso, "[kernel.kallsyms]", false); map__fixup_start(map); map__fixup_end(map); @@ -1711,6 +1712,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); if (err > 0 && !dso__is_kcore(dso)) { + dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; machine__mmap_name(machine, path, sizeof(path)); dso__set_long_name(dso, strdup(path), true); map__fixup_start(map); From 9c00a81b6aafc4ed375a43e7a54e6cf2d720c7c6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:50 +0300 Subject: [PATCH 18/33] perf symbols: Add ability to iterate over a dso's symbols Expose dso__first_symbol() and dso__next_symbol() to make it possible to iterate over a dso's symbols. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-27-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 17 ++++++++++++++++- tools/perf/util/symbol.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 156ae36dfcfc..eb06746b06b2 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -342,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols) return NULL; } +static struct symbol *symbols__next(struct symbol *sym) +{ + struct rb_node *n = rb_next(&sym->rb_node); + + if (n) + return rb_entry(n, struct symbol, rb_node); + + return NULL; +} + struct symbol_name_rb_node { struct rb_node rb_node; struct symbol sym; @@ -412,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso, return symbols__find(&dso->symbols[type], addr); } -static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) +struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) { return symbols__first(&dso->symbols[type]); } +struct symbol *dso__next_symbol(struct symbol *sym) +{ + return symbols__next(sym); +} + struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, const char *name) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 436169dd1d84..ee2d3ccd3ad1 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -240,6 +240,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, const char *name); +struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); +struct symbol *dso__next_symbol(struct symbol *sym); + int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); int modules__parse(const char *filename, void *arg, From 919d86d3a3109d7d4f0d7347f34711ee2f8e6609 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:51 +0300 Subject: [PATCH 19/33] perf session: Flag if the event stream is entirely in memory Flag if the event stream is a file that has been mmapped in one go. This is useful, for example, if a tool needs to keep an event for later reference. If the new flag is set, a pointer to the event can be retained, otherwise the event must be copied. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-28-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 9 ++++++++- tools/perf/util/session.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c2f4ca917469..eac14ce0ae8d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1297,8 +1297,10 @@ int __perf_session__process_events(struct perf_session *session, ui_progress__init(&prog, file_size, "Processing events..."); mmap_size = MMAP_SIZE; - if (mmap_size > file_size) + if (mmap_size > file_size) { mmap_size = file_size; + session->one_mmap = true; + } memset(mmaps, 0, sizeof(mmaps)); @@ -1320,6 +1322,10 @@ remap: mmaps[map_idx] = buf; map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); file_pos = file_offset + head; + if (session->one_mmap) { + session->one_mmap_addr = buf; + session->one_mmap_offset = file_offset; + } more: event = fetch_mmaped_event(session, head, mmap_size, buf); @@ -1365,6 +1371,7 @@ out_err: ui_progress__finish(); perf_session__warn_about_errors(session, tool); perf_session_free_sample_buffers(session); + session->one_mmap = false; return err; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 3140f8ae6148..0321013bd9fd 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -36,6 +36,9 @@ struct perf_session { struct trace_event tevent; struct events_stats stats; bool repipe; + bool one_mmap; + void *one_mmap_addr; + u64 one_mmap_offset; struct ordered_samples ordered_samples; struct perf_data_file *file; }; From a8a8f3eb5de55aeaf007c18572668e8ec463547b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:52 +0300 Subject: [PATCH 20/33] perf evlist: Pass mmap parameters in a struct In preparation for adding more mmap parameters, pass existing parameters in a struct. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-29-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 46 +++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c51223ac25f4..814e954c1318 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) return evlist->mmap != NULL ? 0 : -ENOMEM; } -static int __perf_evlist__mmap(struct perf_evlist *evlist, - int idx, int prot, int mask, int fd) +struct mmap_params { + int prot; + int mask; +}; + +static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, + struct mmap_params *mp, int fd) { evlist->mmap[idx].prev = 0; - evlist->mmap[idx].mask = mask; - evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, + evlist->mmap[idx].mask = mp->mask; + evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, MAP_SHARED, fd, 0); if (evlist->mmap[idx].base == MAP_FAILED) { pr_debug2("failed to mmap perf event ring buffer, error %d\n", @@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, } static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, - int prot, int mask, int cpu, int thread, - int *output) + struct mmap_params *mp, int cpu, + int thread, int *output) { struct perf_evsel *evsel; @@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (*output == -1) { *output = fd; - if (__perf_evlist__mmap(evlist, idx, prot, mask, - *output) < 0) + if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0) return -1; } else { if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) @@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, return 0; } -static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, - int mask) +static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, + struct mmap_params *mp) { int cpu, thread; int nr_cpus = cpu_map__nr(evlist->cpus); @@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int output = -1; for (thread = 0; thread < nr_threads; thread++) { - if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, - cpu, thread, &output)) + if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, + thread, &output)) goto out_unmap; } } @@ -677,8 +681,8 @@ out_unmap: return -1; } -static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, - int mask) +static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, + struct mmap_params *mp) { int thread; int nr_threads = thread_map__nr(evlist->threads); @@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, for (thread = 0; thread < nr_threads; thread++) { int output = -1; - if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, - thread, &output)) + if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, + &output)) goto out_unmap; } @@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, struct perf_evsel *evsel; const struct cpu_map *cpus = evlist->cpus; const struct thread_map *threads = evlist->threads; - int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; + struct mmap_params mp = { + .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), + }; if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) return -ENOMEM; @@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, evlist->overwrite = overwrite; evlist->mmap_len = perf_evlist__mmap_size(pages); pr_debug("mmap size %zuB\n", evlist->mmap_len); - mask = evlist->mmap_len - page_size - 1; + mp.mask = evlist->mmap_len - page_size - 1; evlist__for_each(evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && @@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, } if (cpu_map__empty(cpus)) - return perf_evlist__mmap_per_thread(evlist, prot, mask); + return perf_evlist__mmap_per_thread(evlist, &mp); - return perf_evlist__mmap_per_cpu(evlist, prot, mask); + return perf_evlist__mmap_per_cpu(evlist, &mp); } int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) From f6d313699a9612a30fabe05bf2c9302c1408b5cf Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:53 +0300 Subject: [PATCH 21/33] perf tools: Add feature test for __sync_val_compare_and_swap Add a feature test for __sync_val_compare_and_swap() and __sync_bool_compare_and_swap() Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-30-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/config/Makefile | 6 ++++++ tools/perf/config/feature-checks/Makefile | 4 ++++ tools/perf/config/feature-checks/test-all.c | 5 +++++ .../feature-checks/test-sync-compare-and-swap.c | 14 ++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tools/perf/config/feature-checks/test-sync-compare-and-swap.c diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b7f42d577c4e..1f67aa02d240 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -164,6 +164,7 @@ CORE_FEATURE_TESTS = \ backtrace \ dwarf \ fortify-source \ + sync-compare-and-swap \ glibc \ gtk2 \ gtk2-infobar \ @@ -199,6 +200,7 @@ LIB_FEATURE_TESTS = \ VF_FEATURE_TESTS = \ backtrace \ fortify-source \ + sync-compare-and-swap \ gtk2-infobar \ libelf-getphdrnum \ libelf-mmap \ @@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE) CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +ifeq ($(feature-sync-compare-and-swap), 1) + CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT +endif + ifndef NO_BIONIC $(call feature_check,bionic) ifeq ($(feature-bionic), 1) diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 64c84e5f0514..6088f8d8a434 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -5,6 +5,7 @@ FILES= \ test-bionic.bin \ test-dwarf.bin \ test-fortify-source.bin \ + test-sync-compare-and-swap.bin \ test-glibc.bin \ test-gtk2.bin \ test-gtk2-infobar.bin \ @@ -141,6 +142,9 @@ test-timerfd.bin: test-libdw-dwarf-unwind.bin: $(BUILD) +test-sync-compare-and-swap.bin: + $(BUILD) -Werror + -include *.d ############################### diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index fe5c1e5c952f..a7d022e161c0 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c @@ -89,6 +89,10 @@ # include "test-libdw-dwarf-unwind.c" #undef main +#define main main_test_sync_compare_and_swap +# include "test-sync-compare-and-swap.c" +#undef main + int main(int argc, char *argv[]) { main_test_libpython(); @@ -111,6 +115,7 @@ int main(int argc, char *argv[]) main_test_timerfd(); main_test_stackprotector_all(); main_test_libdw_dwarf_unwind(); + main_test_sync_compare_and_swap(argc, argv); return 0; } diff --git a/tools/perf/config/feature-checks/test-sync-compare-and-swap.c b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file mode 100644 index 000000000000..c34d4ca4af56 --- /dev/null +++ b/tools/perf/config/feature-checks/test-sync-compare-and-swap.c @@ -0,0 +1,14 @@ +#include + +volatile uint64_t x; + +int main(int argc, char *argv[]) +{ + uint64_t old, new = argc; + + argv = argv; + do { + old = __sync_val_compare_and_swap(&x, 0, 0); + } while (!__sync_bool_compare_and_swap(&x, old, new)); + return old == new; +} From ea8e08a16a1e6566be3f775c0bd351fa52ab6b9d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:54 +0300 Subject: [PATCH 22/33] perf tools: Add option macro OPT_CALLBACK_OPTARG Add an option macro that is the same as OPT_CALLBACK except that the argument is optional and it is possible to associate additional data with it. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-31-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index d8dac8ac5f37..b59ba858e73d 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h @@ -98,6 +98,7 @@ struct option { parse_opt_cb *callback; intptr_t defval; bool *set; + void *data; }; #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) @@ -131,6 +132,10 @@ struct option { { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} +#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \ + { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \ + .value = (v), (a), .help = (h), .callback = (f), \ + .flags = PARSE_OPT_OPTARG, .data = (d) } /* parse_options() will filter out the processed options and leave the * non-option argments in argv[]. From 6ff1ce763921f605aaf98c7a828b7df24d6923dc Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:56 +0300 Subject: [PATCH 23/33] perf evsel: Add 'no_aux_samples' option Add an option to prevent additional samples being added to a selected event by perf_evsel__config(). This is needed when using the sched_switch tracepoint to follow object code execution. Since sched_switch will be used only for switch information, additional sampling is wasteful. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-33-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 6 +++--- tools/perf/util/evsel.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b760d32aae06..40626e5fc1c0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->mmap_data = track; } - if (opts->call_graph_enabled) + if (opts->call_graph_enabled && !evsel->no_aux_samples) perf_evsel__config_callgraph(evsel, opts); if (target__has_cpu(&opts->target)) @@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) target__has_cpu(&opts->target) || per_cpu)) perf_evsel__set_sample_bit(evsel, TIME); - if (opts->raw_samples) { + if (opts->raw_samples && !evsel->no_aux_samples) { perf_evsel__set_sample_bit(evsel, TIME); perf_evsel__set_sample_bit(evsel, RAW); perf_evsel__set_sample_bit(evsel, CPU); @@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->watermark = 0; attr->wakeup_events = 1; } - if (opts->branch_stack) { + if (opts->branch_stack && !evsel->no_aux_samples) { perf_evsel__set_sample_bit(evsel, BRANCH_STACK); attr->branch_sample_type = opts->branch_stack; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a52e9a5bb2d0..8dfec05bcec2 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -83,6 +83,7 @@ struct perf_evsel { int is_pos; bool supported; bool needs_swap; + bool no_aux_samples; /* parse modifier helper */ int exclude_GH; int nr_members; From 2afd2bcfc3a026d6e4c2184bf41ccd74eb05758b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:02:57 +0300 Subject: [PATCH 24/33] perf evsel: Add 'immediate' option Add an option to cause a selected event to be enabled immediately when configured by perf_evsel__config(). This is needed when using the sched_switch tracepoint to follow object code execution. By having sched_switch enabled immediately the first sched_switch event precedes the start of other tracing. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-34-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 5 +++++ tools/perf/util/evsel.h | 1 + 2 files changed, 6 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 40626e5fc1c0..90f58cdd0fb0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && !opts->initial_delay) attr->enable_on_exec = 1; + + if (evsel->immediate) { + attr->disabled = 0; + attr->enable_on_exec = 0; + } } int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8dfec05bcec2..d7f93ce0ebc1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -84,6 +84,7 @@ struct perf_evsel { bool supported; bool needs_swap; bool no_aux_samples; + bool immediate; /* parse modifier helper */ int exclude_GH; int nr_members; From 29ce36121e6738012aaf00d983d25260627f2b0d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 16 Jul 2014 11:07:13 +0300 Subject: [PATCH 25/33] perf machine: Fix map groups of threads with unknown pids Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405498033-23817-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 57 ++++++++++++++++++++++++++++++++++----- tools/perf/util/map.c | 14 ++++++++++ tools/perf/util/map.h | 1 + 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5b8087728f28..5484fa4385fc 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) return; } +static void machine__update_thread_pid(struct machine *machine, + struct thread *th, pid_t pid) +{ + struct thread *leader; + + if (pid == th->pid_ || pid == -1 || th->pid_ != -1) + return; + + th->pid_ = pid; + + if (th->pid_ == th->tid) + return; + + leader = machine__findnew_thread(machine, th->pid_, th->pid_); + if (!leader) + goto out_err; + + if (!leader->mg) + leader->mg = map_groups__new(); + + if (!leader->mg) + goto out_err; + + if (th->mg == leader->mg) + return; + + if (th->mg) { + /* + * Maps are created from MMAP events which provide the pid and + * tid. Consequently there never should be any maps on a thread + * with an unknown pid. Just print an error if there are. + */ + if (!map_groups__empty(th->mg)) + pr_err("Discarding thread maps for %d:%d\n", + th->pid_, th->tid); + map_groups__delete(th->mg); + } + + th->mg = map_groups__get(leader->mg); + + return; + +out_err: + pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); +} + static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid, bool create) @@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine, * so most of the time we dont have to look up * the full rbtree: */ - if (machine->last_match && machine->last_match->tid == tid) { - if (pid != -1 && pid != machine->last_match->pid_) - machine->last_match->pid_ = pid; - return machine->last_match; + th = machine->last_match; + if (th && th->tid == tid) { + machine__update_thread_pid(machine, th, pid); + return th; } while (*p != NULL) { @@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, if (th->tid == tid) { machine->last_match = th; - if (pid != -1 && pid != th->pid_) - th->pid_ = pid; + machine__update_thread_pid(machine, th, pid); return th; } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 25c571f4cba6..7af14807ee90 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg) } } +bool map_groups__empty(struct map_groups *mg) +{ + int i; + + for (i = 0; i < MAP__NR_TYPES; ++i) { + if (maps__first(&mg->maps[i])) + return false; + if (!list_empty(&mg->removed_maps[i])) + return false; + } + + return true; +} + struct map_groups *map_groups__new(void) { struct map_groups *mg = malloc(sizeof(*mg)); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 7758c72522ef..5806a906198b 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -66,6 +66,7 @@ struct map_groups { struct map_groups *map_groups__new(void); void map_groups__delete(struct map_groups *mg); +bool map_groups__empty(struct map_groups *mg); static inline struct map_groups *map_groups__get(struct map_groups *mg) { From 9608b84e4dd95341b88cad646b114811f5bccbba Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 16 Jul 2014 10:19:43 +0300 Subject: [PATCH 26/33] perf thread: Allow deletion of a thread with no map groups It needs to be possible to call thread__delete() on a thread with no map groups. This is needed for a subsequent patch which deletes a thread on the error path before map groups have been attached. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405495184-20441-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Adrian Hunter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/thread.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 7a32f447a8e7..b9c36ef42d2f 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -60,8 +60,10 @@ void thread__delete(struct thread *thread) { struct comm *comm, *tmp; - map_groups__put(thread->mg); - thread->mg = NULL; + if (thread->mg) { + map_groups__put(thread->mg); + thread->mg = NULL; + } list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { list_del(&comm->list); comm__free(comm); From 418029b7324f8b90ac1dfbc8a44555d6905be761 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 16 Jul 2014 10:19:44 +0300 Subject: [PATCH 27/33] perf machine: Fix leak of 'struct thread' on error path __machine__findnew_thread() creates a 'struct thread' but does not free it on the error path. Fix it. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405495184-20441-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5484fa4385fc..93c8b6fbc799 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -370,8 +370,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine, * within thread__init_map_groups to find the thread * leader and that would screwed the rb tree. */ - if (thread__init_map_groups(th, machine)) + if (thread__init_map_groups(th, machine)) { + thread__delete(th); return NULL; + } } return th; From acebd408bef17169fbf79079b96f0264b535916c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 14 Jul 2014 23:46:47 +0200 Subject: [PATCH 28/33] perf tools: Remove verbose from functions prototypes And use verbose as an global object in following functions: __map_groups__fprintf_maps __map_groups__fprintf_removed_maps map_groups__fprintf_maps map_groups__fprintf Also making map_groups__fprintf_maps static. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1405374411-29012-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/stdio/hist.c | 2 +- tools/perf/util/map.c | 24 ++++++++++++------------ tools/perf/util/map.h | 9 ++++----- tools/perf/util/thread.c | 4 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 90122abd3721..40af0acb4fe9 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -479,7 +479,7 @@ print_entries: if (h->ms.map == NULL && verbose > 1) { __map_groups__fprintf_maps(h->thread->mg, - MAP__FUNCTION, verbose, fp); + MAP__FUNCTION, fp); fprintf(fp, "%.10s end\n", graph_dotted_line); } } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 7af14807ee90..845f627e45f4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -12,6 +12,7 @@ #include "vdso.h" #include "build-id.h" #include "util.h" +#include "debug.h" #include const char *map_type__name[MAP__NR_TYPES] = { @@ -568,8 +569,8 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) return ams->sym ? 0 : -1; } -size_t __map_groups__fprintf_maps(struct map_groups *mg, - enum map_type type, int verbose, FILE *fp) +size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, + FILE *fp) { size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); struct rb_node *nd; @@ -587,17 +588,16 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg, return printed; } -size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) +static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) { size_t printed = 0, i; for (i = 0; i < MAP__NR_TYPES; ++i) - printed += __map_groups__fprintf_maps(mg, i, verbose, fp); + printed += __map_groups__fprintf_maps(mg, i, fp); return printed; } static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, - enum map_type type, - int verbose, FILE *fp) + enum map_type type, FILE *fp) { struct map *pos; size_t printed = 0; @@ -614,23 +614,23 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, } static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, - int verbose, FILE *fp) + FILE *fp) { size_t printed = 0, i; for (i = 0; i < MAP__NR_TYPES; ++i) - printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); + printed += __map_groups__fprintf_removed_maps(mg, i, fp); return printed; } -size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) +size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) { - size_t printed = map_groups__fprintf_maps(mg, verbose, fp); + size_t printed = map_groups__fprintf_maps(mg, fp); printed += fprintf(fp, "Removed maps:\n"); - return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); + return printed + map_groups__fprintf_removed_maps(mg, fp); } int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, - int verbose, FILE *fp) + FILE *fp) { struct rb_root *root = &mg->maps[map->type]; struct rb_node *next = rb_first(root); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 5806a906198b..22d13a219590 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -142,8 +142,8 @@ void map__fixup_end(struct map *map); void map__reloc_vmlinux(struct map *map); -size_t __map_groups__fprintf_maps(struct map_groups *mg, - enum map_type type, int verbose, FILE *fp); +size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, + FILE *fp); void maps__insert(struct rb_root *maps, struct map *map); void maps__remove(struct rb_root *maps, struct map *map); struct map *maps__find(struct rb_root *maps, u64 addr); @@ -153,8 +153,7 @@ void map_groups__init(struct map_groups *mg); void map_groups__exit(struct map_groups *mg); int map_groups__clone(struct map_groups *mg, struct map_groups *parent, enum map_type type); -size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); -size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); +size_t map_groups__fprintf(struct map_groups *mg, FILE *fp); int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, u64 addr); @@ -211,7 +210,7 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg, } int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, - int verbose, FILE *fp); + FILE *fp); struct map *map_groups__find_by_name(struct map_groups *mg, enum map_type type, const char *name); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index b9c36ef42d2f..9692c06a9e21 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -129,12 +129,12 @@ int thread__comm_len(struct thread *thread) size_t thread__fprintf(struct thread *thread, FILE *fp) { return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + - map_groups__fprintf(thread->mg, verbose, fp); + map_groups__fprintf(thread->mg, fp); } void thread__insert_map(struct thread *thread, struct map *map) { - map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); + map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); } From 84f5d36f486609277801e827241396334185d11c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 14 Jul 2014 23:46:48 +0200 Subject: [PATCH 29/33] perf tools: Move pr_* debug macros into debug object Moving pr_* debug macros to have it with in same object as debug variables, becase we will change them to use verbose variable in next patch. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1405374411-29012-3-git-send-email-jolsa@kernel.org [ Add missing debug.h include in python scripting glue and in the libdw unwind lib ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/tests/dwarf-unwind.c | 1 + tools/perf/arch/x86/util/unwind-libunwind.c | 1 + tools/perf/builtin-evlist.c | 1 + tools/perf/builtin-help.c | 1 + tools/perf/builtin-timechart.c | 1 + tools/perf/tests/dso-data.c | 1 + tools/perf/tests/evsel-roundtrip-name.c | 1 + tools/perf/tests/evsel-tp-sched.c | 1 + tools/perf/tests/open-syscall-tp-fields.c | 1 + tools/perf/tests/parse-events.c | 1 + tools/perf/tests/parse-no-sample-id-all.c | 1 + tools/perf/tests/sample-parsing.c | 1 + tools/perf/tests/thread-mg-share.c | 1 + tools/perf/util/data.c | 1 + tools/perf/util/debug.h | 20 ++++++++++++++++++ tools/perf/util/include/linux/kernel.h | 21 ------------------- tools/perf/util/pstack.c | 1 + .../util/scripting-engines/trace-event-perl.c | 1 + .../scripting-engines/trace-event-python.c | 1 + tools/perf/util/trace-event-info.c | 1 + tools/perf/util/trace-event-read.c | 1 + tools/perf/util/unwind-libdw.c | 1 + tools/perf/util/unwind-libunwind.c | 1 + tools/perf/util/util.c | 1 + tools/perf/util/vdso.c | 1 + 25 files changed, 43 insertions(+), 21 deletions(-) diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c index 9f89f899ccc7..d8bbf7ad1681 100644 --- a/tools/perf/arch/x86/tests/dwarf-unwind.c +++ b/tools/perf/arch/x86/tests/dwarf-unwind.c @@ -3,6 +3,7 @@ #include "thread.h" #include "map.h" #include "event.h" +#include "debug.h" #include "tests/tests.h" #define STACK_SIZE 8192 diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index 3261f68c6a7c..db25e93d989c 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -3,6 +3,7 @@ #include #include "perf_regs.h" #include "../../util/unwind.h" +#include "../../util/debug.h" #ifdef HAVE_ARCH_X86_64_SUPPORT int libunwind__arch_reg_id(int regnum) diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index c99e0de7e54a..66e12f55c052 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -15,6 +15,7 @@ #include "util/parse-options.h" #include "util/session.h" #include "util/data.h" +#include "util/debug.h" static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) { diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 178b88ae3d2f..0384d930480b 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -11,6 +11,7 @@ #include "util/parse-options.h" #include "util/run-command.h" #include "util/help.h" +#include "util/debug.h" static struct man_viewer_list { struct man_viewer_list *next; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 04c9c53becad..2f1a5220c090 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -37,6 +37,7 @@ #include "util/svghelper.h" #include "util/tool.h" #include "util/data.h" +#include "util/debug.h" #define SUPPORT_OLD_POWER_EVENTS 1 #define PWR_EVENT_EXIT -1 diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 630808cd7cc2..caaf37f079b1 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -10,6 +10,7 @@ #include "machine.h" #include "symbol.h" #include "tests.h" +#include "debug.h" static char *test_file(int size) { diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 465cdbc345cf..b8d8341b383e 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -2,6 +2,7 @@ #include "evsel.h" #include "parse-events.h" #include "tests.h" +#include "debug.h" static int perf_evsel__roundtrip_cache_name_test(void) { diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 35d7fdb2328d..52162425c969 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -1,6 +1,7 @@ #include #include "evsel.h" #include "tests.h" +#include "debug.h" static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, int size, bool should_be_signed) diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index c505ef2af245..0785b64ffd6c 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c @@ -3,6 +3,7 @@ #include "evsel.h" #include "thread_map.h" #include "tests.h" +#include "debug.h" int test__syscall_open_tp_fields(void) { diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index deba66955f8c..5941927a4b7f 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -5,6 +5,7 @@ #include #include #include "tests.h" +#include "debug.h" #include #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 905019f9b740..2c63ea658541 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -7,6 +7,7 @@ #include "evlist.h" #include "header.h" #include "util.h" +#include "debug.h" static int process_event(struct perf_evlist **pevlist, union perf_event *event) { diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 7ae8d17db3d9..ca292f9a4ae2 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -4,6 +4,7 @@ #include "util.h" #include "event.h" #include "evsel.h" +#include "debug.h" #include "tests.h" diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c index 2b2e0dbe114f..b028499dd3cf 100644 --- a/tools/perf/tests/thread-mg-share.c +++ b/tools/perf/tests/thread-mg-share.c @@ -2,6 +2,7 @@ #include "machine.h" #include "thread.h" #include "map.h" +#include "debug.h" int test__thread_mg_share(void) { diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index ee370a7f2444..29d720cf5844 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -7,6 +7,7 @@ #include "data.h" #include "util.h" +#include "debug.h" static bool check_pipe(struct perf_data_file *file) { diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 443694c36b03..8a8ceb3ccde9 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -11,6 +11,24 @@ extern int verbose; extern bool quiet, dump_trace; +#ifndef pr_fmt +#define pr_fmt(fmt) fmt +#endif + +#define pr_err(fmt, ...) \ + eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_warning(fmt, ...) \ + eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_info(fmt, ...) \ + eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug(fmt, ...) \ + eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debugN(n, fmt, ...) \ + eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) + int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(union perf_event *event); @@ -19,4 +37,6 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); void pr_stat(const char *fmt, ...); +int eprintf(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 9844c31b7c2b..09e8e7aea7c6 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h @@ -94,27 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...) return (i >= ssize) ? (ssize - 1) : i; } -int eprintf(int level, - const char *fmt, ...) __attribute__((format(printf, 2, 3))); - -#ifndef pr_fmt -#define pr_fmt(fmt) fmt -#endif - -#define pr_err(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warning(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_info(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_debug(fmt, ...) \ - eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_debugN(n, fmt, ...) \ - eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) -#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) - /* * This looks more complex than it should be. But we need to * get the type for the ~ right in round_down (it needs to be diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c index daa17aeb6c63..a126e6cc6e73 100644 --- a/tools/perf/util/pstack.c +++ b/tools/perf/util/pstack.c @@ -6,6 +6,7 @@ #include "util.h" #include "pstack.h" +#include "debug.h" #include #include diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index af7da565a750..b2dba9c0a3a1 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -34,6 +34,7 @@ #include "../event.h" #include "../trace-event.h" #include "../evsel.h" +#include "../debug.h" void boot_Perf__Trace__Context(pTHX_ CV *cv); void boot_DynaLoader(pTHX_ CV *cv); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index b366b48646ca..cbce2545da45 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -27,6 +27,7 @@ #include #include "../../perf.h" +#include "../debug.h" #include "../evsel.h" #include "../util.h" #include "../event.h" diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index c3bba883f5c3..eb72716017ac 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -40,6 +40,7 @@ #include "trace-event.h" #include #include "evsel.h" +#include "debug.h" #define VERSION "0.5" diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index e113e180c48f..ea3fd7fc6f5c 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -36,6 +36,7 @@ #include "../perf.h" #include "util.h" #include "trace-event.h" +#include "debug.h" static int input_fd; diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 5ec80a575b50..7419768c38b1 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -3,6 +3,7 @@ #include #include #include +#include "debug.h" #include "unwind.h" #include "unwind-libdw.h" #include "machine.h" diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 25578b98f5c5..92b56db52471 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -30,6 +30,7 @@ #include "unwind.h" #include "symbol.h" #include "util.h" +#include "debug.h" extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index e4132aeeb780..e52e7461911b 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,5 +1,6 @@ #include "../perf.h" #include "util.h" +#include "debug.h" #include #include #ifdef HAVE_BACKTRACE_SUPPORT diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 0ddb3b8a89ec..290582452da3 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -12,6 +12,7 @@ #include "util.h" #include "symbol.h" #include "linux/string.h" +#include "debug.h" static bool vdso_found; static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; From c95688aac7723c17b2badc23233706b2f02e58ed Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 14 Jul 2014 23:46:49 +0200 Subject: [PATCH 30/33] perf tools: Factor eprintf to allow different debug variables This way we can easily reuse current debug functions for another debug variables other than verbose. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1405374411-29012-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/debug.c | 12 ++++++------ tools/perf/util/debug.h | 12 ++++++------ tools/perf/util/python.c | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 299b55586502..c208d6f56e63 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -16,11 +16,11 @@ int verbose; bool dump_trace = false, quiet = false; -static int _eprintf(int level, const char *fmt, va_list args) +static int _eprintf(int level, int var, const char *fmt, va_list args) { int ret = 0; - if (verbose >= level) { + if (var >= level) { if (use_browser >= 1) ui_helpline__vshow(fmt, args); else @@ -30,13 +30,13 @@ static int _eprintf(int level, const char *fmt, va_list args) return ret; } -int eprintf(int level, const char *fmt, ...) +int eprintf(int level, int var, const char *fmt, ...) { va_list args; int ret; va_start(args, fmt); - ret = _eprintf(level, fmt, args); + ret = _eprintf(level, var, fmt, args); va_end(args); return ret; @@ -51,9 +51,9 @@ void pr_stat(const char *fmt, ...) va_list args; va_start(args, fmt); - _eprintf(1, fmt, args); + _eprintf(1, verbose, fmt, args); va_end(args); - eprintf(1, "\n"); + eprintf(1, verbose, "\n"); } int dump_printf(const char *fmt, ...) diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8a8ceb3ccde9..1cb808123242 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -16,15 +16,15 @@ extern bool quiet, dump_trace; #endif #define pr_err(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) #define pr_warning(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) #define pr_info(fmt, ...) \ - eprintf(0, pr_fmt(fmt), ##__VA_ARGS__) + eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug(fmt, ...) \ - eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) + eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debugN(n, fmt, ...) \ - eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) + eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) @@ -37,6 +37,6 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); void pr_stat(const char *fmt, ...); -int eprintf(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 122669c18ff4..12aa9b0d0ba1 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -14,12 +14,12 @@ */ int verbose; -int eprintf(int level, const char *fmt, ...) +int eprintf(int level, int var, const char *fmt, ...) { va_list args; int ret = 0; - if (verbose >= level) { + if (var >= level) { va_start(args, fmt); ret = vfprintf(stderr, fmt, args); va_end(args); From bbb2cea7e8dd496b41558df1a0ec9205497b7ebf Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 17 Jul 2014 12:55:00 +0200 Subject: [PATCH 31/33] perf tools: Add --debug optionto set debug variable Adding --debug option as a way to setup debug variables. Starting with support for verbose, more will come. It's possible to use it now with report command: $ perf --debug verbose ... $ perf --debug verbose=2 ... I'll need this support to add separated debug variable for ordered events change in order to separate debug output out of standard verbose stream. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140717105500.GG516@krava.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf.txt | 10 ++++++- tools/perf/perf.c | 13 ++++++++- tools/perf/util/debug.c | 44 +++++++++++++++++++++++++++++++ tools/perf/util/debug.h | 2 ++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 0eeb247dc7d2..d240bb2e5b22 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt @@ -8,7 +8,15 @@ perf - Performance analysis tools for Linux SYNOPSIS -------- [verse] -'perf' [--version] [--help] COMMAND [ARGS] +'perf' [--version] [--help] [OPTIONS] COMMAND [ARGS] + +OPTIONS +------- +--debug:: + Setup debug variable (just verbose for now) in value + range (0, 10). Use like: + --debug verbose # sets verbose = 1 + --debug verbose=2 # sets verbose = 2 DESCRIPTION ----------- diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 95c58fc15284..eed3fb2a3af0 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -13,11 +13,12 @@ #include "util/quote.h" #include "util/run-command.h" #include "util/parse-events.h" +#include "util/debug.h" #include #include const char perf_usage_string[] = - "perf [--version] [--help] COMMAND [ARGS]"; + "perf [--version] [--debug variable[=VALUE]] [--help] COMMAND [ARGS]"; const char perf_more_info_string[] = "See 'perf help COMMAND' for more information on a specific command."; @@ -212,6 +213,16 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) printf("%s ", p->cmd); } exit(0); + } else if (!strcmp(cmd, "--debug")) { + if (*argc < 2) { + fprintf(stderr, "No variable specified for --debug.\n"); + usage(perf_usage_string); + } + if (perf_debug_option((*argv)[1])) + usage(perf_usage_string); + + (*argv)++; + (*argc)--; } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(perf_usage_string); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index c208d6f56e63..71d419362634 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -105,3 +105,47 @@ void trace_event(union perf_event *event) } printf(".\n"); } + +static struct debug_variable { + const char *name; + int *ptr; +} debug_variables[] = { + { .name = "verbose", .ptr = &verbose }, + { .name = NULL, } +}; + +int perf_debug_option(const char *str) +{ + struct debug_variable *var = &debug_variables[0]; + char *vstr, *s = strdup(str); + int v = 1; + + vstr = strchr(s, '='); + if (vstr) + *vstr++ = 0; + + while (var->name) { + if (!strcmp(s, var->name)) + break; + var++; + } + + if (!var->name) { + pr_err("Unknown debug variable name '%s'\n", s); + free(s); + return -1; + } + + if (vstr) { + v = atoi(vstr); + /* + * Allow only values in range (0, 10), + * otherwise set 0. + */ + v = (v < 0) || (v > 10) ? 0 : v; + } + + *var->ptr = v; + free(s); + return 0; +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 1cb808123242..89fb6b0f7ab2 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -39,4 +39,6 @@ void pr_stat(const char *fmt, ...); int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); +int perf_debug_option(const char *str); + #endif /* __PERF_DEBUG_H */ From ff527bccd469067a64f4ae9747b9045914667d34 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 14 Jul 2014 23:46:51 +0200 Subject: [PATCH 32/33] perf tools: Remove needless getopt.h includes We don't use getopt.h interfaces. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1405374411-29012-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 1 - tools/perf/util/trace-event-read.c | 1 - 2 files changed, 2 deletions(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 98e304766416..dca9145d704c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index ea3fd7fc6f5c..54d9e9b548a8 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include From 0b437860818dc717f6a9e8a5089223a8414f5fff Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 14 Jul 2014 13:03:03 +0300 Subject: [PATCH 33/33] perf tools: Allow TSC conversion on any arch It is possible to record a perf.data file on one architecture and process it on another. Consequently, TSC conversion functions need to be moved out of the arch directory. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1405332185-4050-40-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 ++ tools/perf/arch/x86/util/tsc.c | 22 +--------------------- tools/perf/arch/x86/util/tsc.h | 3 --- tools/perf/tests/perf-time-to-tsc.c | 3 +-- tools/perf/util/tsc.c | 25 +++++++++++++++++++++++++ tools/perf/util/tsc.h | 11 +++++++++++ 6 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 tools/perf/util/tsc.c create mode 100644 tools/perf/util/tsc.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 90c498378a54..3308b22a1660 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -295,6 +295,7 @@ LIB_H += util/intlist.h LIB_H += util/perf_regs.h LIB_H += util/unwind.h LIB_H += util/vdso.h +LIB_H += util/tsc.h LIB_H += ui/helpline.h LIB_H += ui/progress.h LIB_H += ui/util.h @@ -374,6 +375,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)util/record.o LIB_OBJS += $(OUTPUT)util/srcline.o LIB_OBJS += $(OUTPUT)util/data.o +LIB_OBJS += $(OUTPUT)util/tsc.o LIB_OBJS += $(OUTPUT)ui/setup.o LIB_OBJS += $(OUTPUT)ui/helpline.o diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 40021fa3129b..3655f24c3170 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -6,29 +6,9 @@ #include "../../perf.h" #include #include "../../util/debug.h" +#include "../../util/tsc.h" #include "tsc.h" -u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) -{ - u64 t, quot, rem; - - t = ns - tc->time_zero; - quot = t / tc->time_mult; - rem = t % tc->time_mult; - return (quot << tc->time_shift) + - (rem << tc->time_shift) / tc->time_mult; -} - -u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) -{ - u64 quot, rem; - - quot = cyc >> tc->time_shift; - rem = cyc & ((1 << tc->time_shift) - 1); - return tc->time_zero + quot * tc->time_mult + - ((rem * tc->time_mult) >> tc->time_shift); -} - int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, struct perf_tsc_conversion *tc) { diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h index 2affe0366b59..2edc4d31065c 100644 --- a/tools/perf/arch/x86/util/tsc.h +++ b/tools/perf/arch/x86/util/tsc.h @@ -14,7 +14,4 @@ struct perf_event_mmap_page; int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, struct perf_tsc_conversion *tc); -u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); -u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); - #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 3b7cd4d32dcb..0372f6edca20 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -8,10 +8,9 @@ #include "evsel.h" #include "thread_map.h" #include "cpumap.h" +#include "tsc.h" #include "tests.h" -#include "../arch/x86/util/tsc.h" - #define CHECK__(x) { \ while ((x) < 0) { \ pr_debug(#x " failed!\n"); \ diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c new file mode 100644 index 000000000000..ef4749836ce9 --- /dev/null +++ b/tools/perf/util/tsc.c @@ -0,0 +1,25 @@ +#include +#include + +#include "tsc.h" + +u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) +{ + u64 t, quot, rem; + + t = ns - tc->time_zero; + quot = t / tc->time_mult; + rem = t % tc->time_mult; + return (quot << tc->time_shift) + + (rem << tc->time_shift) / tc->time_mult; +} + +u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) +{ + u64 quot, rem; + + quot = cyc >> tc->time_shift; + rem = cyc & ((1 << tc->time_shift) - 1); + return tc->time_zero + quot * tc->time_mult + + ((rem * tc->time_mult) >> tc->time_shift); +} diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h new file mode 100644 index 000000000000..4eca84887c8a --- /dev/null +++ b/tools/perf/util/tsc.h @@ -0,0 +1,11 @@ +#ifndef __PERF_TSC_H +#define __PERF_TSC_H + +#include + +#include "../arch/x86/util/tsc.h" + +u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); + +#endif