perf: kvm live mode
Subsystems (2)
cover perf: kvm live mode
With the consolidation of the open counters code in December 2012 (late to the party figuring that out) I think all of the past comments on the live mode for perf-kvm have been resolved.
David Ahern (13):
perf evlist: restore methods removed in earlier cleanup perf evlist: move tracepoint processing code to evlist.c perf evlist: add initialzation function for tracepoints perf session: export a few functions for event processing perf top: move CONSOLE_CLEAR to header file
perf kvm: handle realloc failures
perf kvm: split out tracepoints from record args perf stats: fix divide by 0 in variance
perf stats: add max and min stats
perf kvm: add live mode
perf kvm: add min and max stats to results display perf kvm: option to print events that exceed a threshold perf kvm: debug for missing vmexit/vmentry event
tools/perf/builtin-kvm.c | 694 ++++++++++++++++++++++++++++++++++++++++++--- tools/perf/builtin-top.c | 2 - tools/perf/util/evlist.c | 120 ++++++++ tools/perf/util/evlist.h | 10 + tools/perf/util/header.c | 44 --- tools/perf/util/session.c | 15 +- tools/perf/util/session.h | 9 + tools/perf/util/stat.c | 8 +- tools/perf/util/stat.h | 9 + tools/perf/util/top.h | 2 + 10 files changed, 816 insertions(+), 97 deletions(-)
Signature · 1 line
1.7.10.1
PATCH 1/13 perf evlist: restore methods removed in earlier cleanup
e60fc847 removed the perf_evlist__add_tracepoints and helpers, but they are useful for kvm's upcoming live mode.
--- tools/perf/util/evlist.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 3 +++ 2 files changed, 57 insertions(+)
tools/perf/util/evlist.c +54 -0
@@ -195,6 +195,60 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,return perf_evlist__add_attrs (evlist, attrs, nr_attrs); } +static int trace_event__id (const char *evname) +{ +char *filename, *colon; +int err =-1 , fd; + +if (asprintf (&filename,"%s/%s/id" , tracing_events_path, evname) <0 ) +return -1 ; + + colon =strrchr (filename,':' ); +if (colon !=NULL ) + *colon ='/' ; + + fd =open (filename,O_RDONLY ); +if (fd >=0 ) { +char id[16 ]; +if (read (fd, id,sizeof (id)) >0 ) + err =atoi (id); +close (fd); + } + +free (filename); +return err; +} + +int perf_evlist__add_tracepoints (struct perf_evlist *evlist, +const char *const tracepoints[], +size_t nr_tracepoints) +{ +int err; +size_t i; +struct perf_event_attr *attrs =zalloc (nr_tracepoints *sizeof (*attrs)); + +if (attrs ==NULL ) +return -1 ; + +for (i =0 ; i < nr_tracepoints; i++) { + err =trace_event__id (tracepoints[i]); + +if (err <0 ) + goto out_free_attrs; + + attrs[i].type =PERF_TYPE_TRACEPOINT ; + attrs[i].config = err; + attrs[i].sample_type = (PERF_SAMPLE_RAW |PERF_SAMPLE_TIME | +PERF_SAMPLE_CPU |PERF_SAMPLE_PERIOD ); + attrs[i].sample_period =1 ; + } + + err =perf_evlist__add_attrs (evlist, attrs, nr_tracepoints); +out_free_attrs: +free (attrs); +return err; +} +struct perf_evsel *perf_evlist__find_tracepoint_by_id (struct perf_evlist *evlist,int id) {
tools/perf/util/evlist.h +3 -0
@@ -59,6 +59,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);int perf_evlist__add_default (struct perf_evlist *evlist);int __perf_evlist__add_default_attrs (struct perf_evlist *evlist,struct perf_event_attr *attrs,size_t nr_attrs); +int perf_evlist__add_tracepoints (struct perf_evlist *evlist, +const char *const tracepoints[], +size_t nr_tracepoints);#define perf_evlist__add_default_attrs (evlist, array) \ __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
Signature · 1 line
1.7.10.1
PATCH 2/13 perf evlist: move tracepoint processing code to evlist.c
In reply to David AhernPer function names they are more aligned with the evlist code than the header code. Export perf_evlist__prepare_tracepoint_events in the process.
Code move only; no functional changes.
--- tools/perf/util/evlist.c | 39 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 4 ++++ tools/perf/util/header.c | 44 -------------------------------------------- tools/perf/util/session.c | 1 - 4 files changed, 43 insertions(+), 45 deletions(-)
tools/perf/util/evlist.c +39 -0
@@ -195,6 +195,45 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,return perf_evlist__add_attrs (evlist, attrs, nr_attrs); } +static int perf_evsel__prepare_tracepoint_event (struct perf_evsel *evsel, +struct pevent *pevent) +{ +struct event_format *event; +char bf[128 ]; + +/* already prepared */ +if (evsel->tp_format) +return 0 ; + + event =pevent_find_event (pevent, evsel->attr.config); +if (event ==NULL ) +return -1 ; + +if (!evsel->name) { +snprintf (bf,sizeof (bf),"%s:%s" , event->system, event->name); + evsel->name =strdup (bf); +if (evsel->name ==NULL ) +return -1 ; + } + + evsel->tp_format = event; +return 0 ; +} + +int perf_evlist__prepare_tracepoint_events (struct perf_evlist *evlist, +struct pevent *pevent) +{ +struct perf_evsel *pos; + +list_for_each_entry (pos, &evlist->entries, node) { +if (pos->attr.type ==PERF_TYPE_TRACEPOINT && +perf_evsel__prepare_tracepoint_event (pos, pevent)) +return -1 ; + } + +return 0 ; +} +static int trace_event__id (const char *evname) {char *filename, *colon;
tools/perf/util/evlist.h +4 -0
@@ -5,6 +5,7 @@#include <stdio.h> #include "../perf.h" #include "event.h" +#include "event-parse.h" #include "evsel.h" #include "util.h" #include <unistd.h>
@@ -59,6 +60,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);int perf_evlist__add_default (struct perf_evlist *evlist);int __perf_evlist__add_default_attrs (struct perf_evlist *evlist,struct perf_event_attr *attrs,size_t nr_attrs); +int perf_evlist__prepare_tracepoint_events (struct perf_evlist *evlist, +struct pevent *pevent); +int perf_evlist__add_tracepoints (struct perf_evlist *evlist,const char *const tracepoints[],size_t nr_tracepoints);
tools/perf/util/header.c +0 -44
50 lines not on this page · raw message
tools/perf/util/session.c +0 -1
@@ -12,7 +12,6 @@#include "sort.h" #include "util.h" #include "cpumap.h" -#include "event-parse.h" #include "perf_regs.h" #include "vdso.h"
Signature · 1 line
1.7.10.1
PATCH 3/13 perf evlist: add initialzation function for tracepoints
In reply to David AhernHandles initializations typically done as part of processing the file header and HEADER_TRACING_DATA event.
--- tools/perf/util/evlist.c | 27 +++++++++++++++++++++++++++ tools/perf/util/evlist.h | 3 +++ 2 files changed, 30 insertions(+)
tools/perf/util/evlist.c +27 -0
@@ -14,6 +14,7 @@#include "target.h" #include "evlist.h" #include "evsel.h" +#include "trace-event.h" #include <unistd.h> #include "parse-events.h"
@@ -234,6 +235,32 @@ int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,return 0 ; } +int perf_evlist__trace_init (struct perf_evlist *evlist, +struct perf_session *session) +{ +struct tracing_data *tdata; +char temp_file[] ="/tmp/perf-XXXXXXXX" ; +int fd; + + fd =mkstemp (temp_file); +if (fd <0 ) { +pr_err ("mkstemp failed\n" ); +return -1 ; + } +unlink (temp_file); + + tdata =tracing_data_get (&evlist->entries, fd, false); +if (!tdata) +return -1 ; + +lseek (fd,0 ,SEEK_SET ); + (void )trace_report (fd, &session->pevent, false); +tracing_data_put (tdata); + +return perf_evlist__prepare_tracepoint_events (evlist, session->pevent); +} + +static int trace_event__id (const char *evname) {char *filename, *colon;
tools/perf/util/evlist.h +3 -0
@@ -8,6 +8,7 @@#include "event-parse.h" #include "evsel.h" #include "util.h" +#include "session.h" #include <unistd.h> struct pollfd ;
@@ -66,6 +67,8 @@ int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,int perf_evlist__add_tracepoints (struct perf_evlist *evlist,const char *const tracepoints[],size_t nr_tracepoints); +int perf_evlist__trace_init (struct perf_evlist *evlist, +struct perf_session *session);#define perf_evlist__add_default_attrs (evlist, array) \ __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
Signature · 1 line
1.7.10.1
Namhyung Kim
maintainerRe: [PATCH 03/13] perf evlist: add initialzation function for tracepoints
Hi David,
Quoted 3 lines · David Ahern
Handles initializations typically done as part of processing the file header and
HEADER_TRACING_DATAevent.
[SNIP]
Quoted 11 lines
tools/perf/util/evlist.c +11
-0+int perf_evlist__trace_init (struct perf_evlist *evlist, +struct perf_session *session) +{ +struct tracing_data *tdata; +char temp_file[] ="/tmp/perf-XXXXXXXX" ; +int fd; + + fd =mkstemp (temp_file); +if (fd <0 ) { +pr_err ("mkstemp failed\n" ); +return -1 ;
tools/perf/util/evlist.c int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, · line 258
Quoted 10 lines
tools/perf/util/evlist.c +10
-0+ } +unlink (temp_file); + + tdata =tracing_data_get (&evlist->entries, fd, false); +if (!tdata) +return -1 ; + +lseek (fd,0 ,SEEK_SET ); + (void )trace_report (fd, &session->pevent, false); +tracing_data_put (tdata);
I guess you need to close the fd here.
tools/perf/util/evlist.c int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, · line 261
Quoted 3 lines
tools/perf/util/evlist.c +3
-0+ +return perf_evlist__prepare_tracepoint_events (evlist, session->pevent); +}
Thanks,
Namhyung
PATCH 4/13 perf session: export a few functions for event processing
In reply to David AhernAllows kvm live mode to reuse the event processing and ordered samples processing used by the perf-report path.
--- tools/perf/util/session.c | 14 +++++++------- tools/perf/util/session.h | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-)
tools/perf/util/session.c +7 -7
@@ -248,7 +248,7 @@ static int process_finished_round(struct perf_tool *tool,union perf_event *event, struct perf_session *session); -static void perf_tool__fill_defaults (struct perf_tool *tool) +void perf_tool__fill_defaults (struct perf_tool *tool) {if (tool->sample ==NULL ) tool->sample = process_event_sample_stub;
@@ -494,8 +494,8 @@ static int perf_session_deliver_event(struct perf_session *session,struct perf_tool *tool, u64 file_offset); -static int flush_sample_queue (struct perf_session *s, -struct perf_tool *tool) +int flush_sample_queue (struct perf_session *s, +struct perf_tool *tool) {struct ordered_samples *os = &s->ordered_samples;struct list_head *head = &os->samples;
@@ -948,10 +948,10 @@ static void event_swap(union perf_event *event, bool sample_id_all)swap (event, sample_id_all); } -static int perf_session__process_event (struct perf_session *session, -union perf_event *event, -struct perf_tool *tool, -u64 file_offset) +int perf_session__process_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset) {struct perf_sample sample;int ret;
tools/perf/util/session.h +9 -0
@@ -58,6 +58,15 @@ int __perf_session__process_events(struct perf_session *self,int perf_session__process_events (struct perf_session *self,struct perf_tool *tool); +int perf_session__process_event (struct perf_session *session, +union perf_event *event, +struct perf_tool *tool, +u64 file_offset); + +int flush_sample_queue (struct perf_session *s,struct perf_tool *tool); + +void perf_tool__fill_defaults (struct perf_tool *tool); + int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, struct thread *thread, struct ip_callchain *chain,
Signature · 1 line
1.7.10.1
Re: [PATCH 04/13] perf session: export a few functions for event processing
Quoted 30 lines · David Ahern
Allows kvm live mode to reuse the event processing and ordered samples processing used by the perf-report path.
Signed-off-by David Ahern <[email protected]>Cc Arnaldo Carvalho de Melo <[email protected]>Cc Ingo Molnar <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Jiri Olsa <[email protected]>Cc Namhyung Kim <[email protected]>Cc Xiao Guangrong <[email protected]>--- tools/perf/util/session.c | 14 +++++++------- tools/perf/util/session.h | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-)tools/perf/util/session.c +1
-1@@ -248,7 +248,7 @@ static int process_finished_round(struct perf_tool *tool,union perf_event *event, struct perf_session *session); -static void perf_tool__fill_defaults (struct perf_tool *tool) +void perf_tool__fill_defaults (struct perf_tool *tool) {if (tool->sample ==NULL ) tool->sample = process_event_sample_stub;
tools/perf/util/session.c static int perf_session_deliver_event(struct perf_session *session, · line 498
Quoted 7 lines
tools/perf/util/session.c +2
-2@@ -494,8 +494,8 @@ static int perf_session_deliver_event(struct perf_session *session,struct perf_tool *tool, u64 file_offset); -static int flush_sample_queue (struct perf_session *s, -struct perf_tool *tool) +int flush_sample_queue (struct perf_session *s, +struct perf_tool *tool)
hm, can't see flush_sample_queue being used globaly
jirka
Re: [PATCH 04/13] perf session: export a few functions for event processing
Quoted 10 lines · Jiri Olsa
tools/perf/util/session.c static int perf_session_deliver_event(struct perf_session *session, · line 498
Quoted 8 lines
tools/perf/util/session.c +2
-2@@ -494,8 +494,8 @@ static int perf_session_deliver_event(struct perf_session *session,struct perf_tool *tool, u64 file_offset); -static int flush_sample_queue (struct perf_session *s, -struct perf_tool *tool) +int flush_sample_queue (struct perf_session *s, +struct perf_tool *tool)hm, can't see
flush_sample_queuebeing used globaly
oops, moved to finish_round and forgot to remove this export.
David
PATCH 5/13 perf top: move CONSOLE_CLEAR to header file
In reply to David AhernFor use with kvm-live mode.
--- tools/perf/builtin-top.c | 2 -- tools/perf/util/top.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/builtin-top.c +0 -2
@@ -243,8 +243,6 @@ out_unlock:pthread_mutex_unlock (¬es->lock); } -static const char CONSOLE_CLEAR [] ="[H[2J" ; -static struct hist_entry *perf_evsel__add_hist_entry (struct perf_evsel *evsel,struct addr_location *al,struct perf_sample *sample)
tools/perf/util/top.h +2 -0
@@ -38,6 +38,8 @@ struct perf_top { const char *sym_filter; }; +#define CONSOLE_CLEAR "[H[2J" +size_t perf_top__header_snprintf (struct perf_top *top,char *bf,size_t size);void perf_top__reset_sample_counters (struct perf_top *top);#endif /* __PERF_TOP_H */
Signature · 1 line
1.7.10.1
PATCH 6/13 perf kvm: handle realloc failures
In reply to David AhernSave previous pointer and free on failure.
--- tools/perf/builtin-kvm.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/builtin-kvm.c +3 -0
@@ -328,6 +328,7 @@ static int kvm_events_hash_fn(u64 key)static bool kvm_event_expand (struct kvm_event *event,int vcpu_id) {int old_max_vcpu = event->max_vcpu; +void *prev;if (vcpu_id < event->max_vcpu)return true;
@@ -335,9 +336,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)while (event->max_vcpu <= vcpu_id) event->max_vcpu +=DEFAULT_VCPU_NUM ; + prev = event->vcpu; event->vcpu =realloc (event->vcpu, event->max_vcpu *sizeof (*event->vcpu));if (!event->vcpu) { +free (prev);pr_err ("Not enough memory\n" );return false; }
Signature · 1 line
1.7.10.1
PATCH 7/13 perf kvm: split out tracepoints from record args
In reply to David AhernNeeded by kvm live command. Make record_args a local while we are messing with the args.
--- tools/perf/builtin-kvm.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)
tools/perf/builtin-kvm.c +19 -11
@@ -801,16 +801,11 @@ exit:return ret; } -static const char *const record_args[] = { -"record" , -"-R" , -"-f" , -"-m" ,"1024" , -"-c" ,"1" , -"-e" ,"kvm:kvm_entry" , -"-e" ,"kvm:kvm_exit" , -"-e" ,"kvm:kvm_mmio" , -"-e" ,"kvm:kvm_pio" , +static const char *const kvm_events_tp[] = { +"kvm:kvm_entry" , +"kvm:kvm_exit" , +"kvm:kvm_mmio" , +"kvm:kvm_pio" , };#define STRDUP_FAIL_EXIT (s) \
@@ -826,8 +821,16 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) {unsigned int rec_argc, i, j;const char **rec_argv; +const char *const record_args[] = { +"record" , +"-R" , +"-f" , +"-m" ,"1024" , +"-c" ,"1" , + }; - rec_argc =ARRAY_SIZE (record_args) + argc +2 ; + rec_argc =ARRAY_SIZE (record_args) + argc +2 + +2 *ARRAY_SIZE (kvm_events_tp); rec_argv =calloc (rec_argc +1 ,sizeof (char *));if (rec_argv ==NULL )
@@ -836,6 +839,11 @@ 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++) { + rec_argv[i++] ="-e" ; + rec_argv[i++] =STRDUP_FAIL_EXIT (kvm_events_tp[j]); + } + rec_argv[i++] =STRDUP_FAIL_EXIT ("-o" ); rec_argv[i++] =STRDUP_FAIL_EXIT (kvm->file_name);
Signature · 1 line
1.7.10.1
Re: [PATCH 07/13] perf kvm: split out tracepoints from record args
Quoted 60 lines · David Ahern
Needed by kvm live command. Make
record_argsa local while we are messing with the args.Signed-off-by David Ahern <[email protected]>Cc Arnaldo Carvalho de Melo <[email protected]>Cc Ingo Molnar <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Jiri Olsa <[email protected]>Cc Namhyung Kim <[email protected]>Cc Xiao Guangrong <[email protected]>--- tools/perf/builtin-kvm.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)tools/perf/builtin-kvm.c +14
-11@@ -801,16 +801,11 @@ exit:return ret; } -static const char *const record_args[] = { -"record" , -"-R" , -"-f" , -"-m" ,"1024" , -"-c" ,"1" , -"-e" ,"kvm:kvm_entry" , -"-e" ,"kvm:kvm_exit" , -"-e" ,"kvm:kvm_mmio" , -"-e" ,"kvm:kvm_pio" , +static const char *const kvm_events_tp[] = { +"kvm:kvm_entry" , +"kvm:kvm_exit" , +"kvm:kvm_mmio" , +"kvm:kvm_pio" , };#define STRDUP_FAIL_EXIT (s) \@@ -826,8 +821,16 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) {unsigned int rec_argc, i, j;const char **rec_argv; +const char *const record_args[] = { +"record" , +"-R" , +"-f" , +"-m" ,"1024" , +"-c" ,"1" , + }; - rec_argc =ARRAY_SIZE (record_args) + argc +2 ; + rec_argc =ARRAY_SIZE (record_args) + argc +2 + +2 *ARRAY_SIZE (kvm_events_tp); rec_argv =calloc (rec_argc +1 ,sizeof (char *));if (rec_argv ==NULL )
tools/perf/builtin-kvm.c kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) · line 846
Quoted 8 lines
tools/perf/builtin-kvm.c +5
-0@@ -836,6 +839,11 @@ 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++) { + rec_argv[i++] ="-e" ; + rec_argv[i++] =STRDUP_FAIL_EXIT (kvm_events_tp[j]); + } +
just curious.. I dont understand why it needs to be dynamic?
jirka
Re: [PATCH 07/13] perf kvm: split out tracepoints from record args
Quoted 10 lines · Jiri Olsa
tools/perf/builtin-kvm.c kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) · line 846
Quoted 5 lines
tools/perf/builtin-kvm.c +5
-0+for (j =0 ; j <ARRAY_SIZE (kvm_events_tp); j++) { + rec_argv[i++] ="-e" ; + rec_argv[i++] =STRDUP_FAIL_EXIT (kvm_events_tp[j]); + } +just curious.. I dont understand why it needs to be dynamic?
jirka
passing a new set of args to cmd_record -- what the user passed in augmented with the tracepoints needed for kvm stat.
David
PATCH 8/13 perf stats: fix divide by 0 in variance
In reply to David AhernNumber of samples needs to be greater 1 to have a variance. Fixes nan% in perf-kvm-live output.
--- tools/perf/util/stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/stat.c +1 -1
@@ -37,7 +37,7 @@ double stddev_stats(struct stats *stats) {double variance, variance_mean; -if (!stats->n) +if (stats->n <2 )return 0.0 ; variance = stats->M2 / (stats->n -1 );
Signature · 1 line
1.7.10.1
PATCH 9/13 perf stats: add max and min stats
In reply to David AhernNeed an initialization function to set min to -1 to differentiate from an actual min of 0.
--- tools/perf/util/stat.c | 6 ++++++ tools/perf/util/stat.h | 9 +++++++++ 2 files changed, 15 insertions(+)
tools/perf/util/stat.c +6 -0
@@ -10,6 +10,12 @@ void update_stats(struct stats *stats, u64 val) delta = val - stats->mean; stats->mean += delta / stats->n; stats->M2 += delta*(val - stats->mean); + +if (val > stats->max) + stats->max = val; + +if (val < stats->min) + stats->min = val; }double avg_stats (struct stats *stats)
tools/perf/util/stat.h +9 -0
@@ -6,6 +6,7 @@struct stats {double n, mean, M2; +u64 max, min; };void update_stats (struct stats *stats,u64 val);
@@ -13,4 +14,12 @@ double avg_stats(struct stats *stats);double stddev_stats (struct stats *stats);double rel_stddev_stats (double stddev,double avg); +static inline void init_stats (struct stats *stats) +{ + stats->n =0.0 ; + stats->mean =0.0 ; + stats->M2 =0.0 ; + stats->min = (u64) -1 ; + stats->max =0 ; +}#endif
Signature · 1 line
1.7.10.1
PATCH 10/13 perf kvm: add live mode
In reply to David Ahernperf kvm stat currently requires back to back record and report commands to see stats. e.g,.
perf kvm stat record -p $pid -- sleep 1
perf kvm stat report
This is inconvenvient for on box monitoring of a VM. This patch introduces a 'live' mode that in effect combines the record plus report into one command. e.g., to monitor a single VM:
perf kvm stat live -p $pid
or all VMs:
perf kvm stat live
Same stats options for the record+report path work with the live mode. Display rate defaults to 1 second and can be changed using the -d option.
--- tools/perf/builtin-kvm.c | 609 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 583 insertions(+), 26 deletions(-)
tools/perf/builtin-kvm.c +583 -26
@@ -2,6 +2,7 @@#include "perf.h" #include "util/evsel.h" +#include "util/evlist.h" #include "util/util.h" #include "util/cache.h" #include "util/symbol.h"
@@ -15,9 +16,12 @@#include <lk/debugfs.h> #include "util/tool.h" #include "util/stat.h" +#include "util/top.h" #include <sys/prctl.h> +#include <sys/timerfd.h> +#include <termios.h> #include <semaphore.h> #include <pthread.h> #include <math.h>
@@ -82,6 +86,8 @@ struct exit_reasons_table {struct perf_kvm_stat {struct perf_tool tool; +struct perf_record_opts opts; +struct perf_evlist *evlist;struct perf_session *session;const char *file_name;
@@ -96,10 +102,16 @@ struct perf_kvm_stat {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;struct rb_root result; + +int timerfd; +unsigned int display_time; +bool live; };
@@ -320,6 +332,23 @@ static void init_kvm_event_record(struct perf_kvm_stat *kvm)INIT_LIST_HEAD (&kvm->kvm_events_cache[i]); } +static void clear_events_cache_stats (struct list_head *kvm_events_cache) +{ +struct list_head *head; +struct kvm_event *event; +unsigned int i; + +for (i =0 ; i <EVENTS_CACHE_SIZE ; i++) { + head = &kvm_events_cache[i]; +list_for_each_entry (event, head, hash_entry) { +/* reset stats for event */ +memset (&event->total,0 ,sizeof (event->total)); +memset (event->vcpu,0 , + event->max_vcpu *sizeof (*event->vcpu)); + } + } +} +static int kvm_events_hash_fn (u64 key) {return key & (EVENTS_CACHE_SIZE -1 );
@@ -472,7 +501,11 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, vcpu_record->last_event =NULL ; vcpu_record->start_time =0 ; -BUG_ON (timestamp < time_begin); +/* seems to happen once in a while during live mode */ +if (timestamp < time_begin) { +pr_debug ("End time before begin time; skipping event.\n" ); +return true; + } time_diff = timestamp - time_begin;return update_kvm_event (event, vcpu, time_diff);
@@ -639,24 +672,60 @@ static struct kvm_event *pop_from_result(struct rb_root *result) return container_of(node, struct kvm_event, rb); } -static void print_vcpu_info (int vcpu) +static void print_vcpu_info (struct perf_kvm_stat *kvm) { +int vcpu = kvm->trace_vcpu; +pr_info ("Analyze events for " ); +if (kvm->live) { +if (kvm->opts.target.system_wide) +pr_info ("all VMs, " ); +else if (kvm->opts.target.pid) +pr_info ("pid(s) %s, " , kvm->opts.target.pid); +else if (kvm->opts.target.tid) +pr_info ("tid(s) %s, " , kvm->opts.target.tid); +else if (kvm->opts.target.cpu_list) +pr_info ("host cpu(s) %s, " , kvm->opts.target.cpu_list); +else +pr_info ("dazed and confused on what is monitored, " ); + } +if (vcpu ==-1 )pr_info ("all VCPUs:\n\n" );else pr_info ("VCPU %d:\n\n" , vcpu); } +static void show_timeofday (void ) +{ +char date[64 ]; +struct timeval tv; +struct tm ltime; + +gettimeofday (&tv,NULL ); +if (localtime_r (&tv.tv_sec, <ime)) { +strftime (date,sizeof (date),"%H:%M:%S" , <ime); +pr_info ("%s.%06ld" , date, tv.tv_usec); + }else +pr_info ("00:00:00.000000" ); + +return ; +} +static void print_result (struct perf_kvm_stat *kvm) {char decode[20 ];struct kvm_event *event;int vcpu = kvm->trace_vcpu; +if (kvm->live) { +puts (CONSOLE_CLEAR ); +show_timeofday (); + } +pr_info ("\n\n" ); -print_vcpu_info (vcpu); +print_vcpu_info (kvm);pr_info ("%20s " , kvm->events_ops->name);pr_info ("%10s " ,"Samples" );pr_info ("%9s " ,"Samples%" );
@@ -683,6 +752,20 @@ static void print_result(struct perf_kvm_stat *kvm)pr_info ("\nTotal Samples:%" PRIu64", Total events handled time:%.2fus.\n\n" , kvm->total_count, kvm->total_time /1e3 ); + +if (kvm->lost_events) +pr_info ("\nLost events: %" PRIu64"\n\n" , kvm->lost_events); +} + +static int process_lost_event (struct perf_tool *tool, +union perf_event *event__maybe_unused , +struct perf_sample *sample__maybe_unused , +struct machine *machine__maybe_unused ) +{ + struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool); + + kvm->lost_events++; +return 0 ; } static int process_sample_event(struct perf_tool *tool,
@@ -707,10 +790,20 @@ static int process_sample_event(struct perf_tool *tool,return 0 ; } -static int get_cpu_isa (struct perf_session *session) +static int cpu_isa_config (struct perf_kvm_stat *kvm) { -char *cpuid = session->header.env.cpuid; -int isa; +char buf[64 ], *cpuid; +int err, isa; + +if (kvm->live) { + err =get_cpuid (buf,sizeof (buf)); +if (err !=0 ) { +pr_err ("Failed to look up CPU type (Intel or AMD)\n" ); +return err; + } + cpuid = buf; + }else + cpuid = kvm->session->header.env.cpuid;if (strstr (cpuid,"Intel" )) isa =1 ;
@@ -718,10 +811,345 @@ static int get_cpu_isa(struct perf_session *session) isa =0 ; else {pr_err ("CPU %s is not supported.\n" , cpuid); - isa = -ENOTSUP ; +return -ENOTSUP ; + } + +if (isa ==1 ) { + kvm->exit_reasons = vmx_exit_reasons; + kvm->exit_reasons_size =ARRAY_SIZE (vmx_exit_reasons); + kvm->exit_reasons_isa ="VMX" ; } -return isa; +return 0 ; +} + +static bool verify_vcpu (int vcpu) +{ +int nr_cpus; + +if (vcpu !=-1 && vcpu <0 ) { +pr_err ("Invalid vcpu:%d.\n" , vcpu); +return false; + } + + nr_cpus =sysconf (_SC_NPROCESSORS_ONLN); +if ((nr_cpus >0 ) && (vcpu > nr_cpus -1 )) { +pr_err ("Invalid vcpu:%d.\n" , vcpu); +return false; + } + +return true; +} + +#define PERF_KVM__MAX_EVENTS_PER_MMAP 1000 + +static s64 perf_kvm__mmap_read_idx (struct perf_kvm_stat *kvm,int idx) +{ +union perf_event *event; +s64 n =0 ; +int err; + +while ((event =perf_evlist__mmap_read (kvm->evlist, idx)) !=NULL ) { + err =perf_session__process_event (kvm->session, event, + &kvm->tool,0 ); +if (err) { +pr_err ("Failed to process event\n" ); +return err; + } + n++; + +/* limit events per mmap handled all at once */ +if (n ==PERF_KVM__MAX_EVENTS_PER_MMAP ) +break ; + } + +return n; +} + +static int perf_kvm__mmap_read (struct perf_kvm_stat *kvm) +{ +int i, err, throttled =0 ; +s64 n, ntotal =0 ; + +for (i =0 ; i < kvm->evlist->nr_mmaps; i++) { + n =perf_kvm__mmap_read_idx (kvm, i); +if (n <0 ) +return -1 ; + ntotal += n; +if (n ==PERF_KVM__MAX_EVENTS_PER_MMAP ) + throttled =1 ; + } + +/* flush queue after each round in which we processed events */ +if (ntotal) { + err = kvm->tool.finished_round (&kvm->tool,NULL , kvm->session); +if (err) { +if (kvm->lost_events) +pr_info ("\nLost events: %" PRIu64"\n\n" , + kvm->lost_events); +return err; + } + } + +return throttled; +} + +static volatile int done; + +static void sig_handler (int sig__maybe_unused ) +{ + done =1 ; +} + +static int perf_kvm__timerfd_create (struct perf_kvm_stat *kvm) +{ +struct itimerspec new_value; +struct timespec now; +int rc =-1 ; + + kvm->timerfd =timerfd_create (CLOCK_MONOTONIC ,TFD_NONBLOCK ); +if (kvm->timerfd <0 ) { +pr_err ("timerfd_create failed\n" ); + goto out; + } + +if (clock_gettime (CLOCK_MONOTONIC , &now) !=0 ) { +pr_err ("clock_gettime failed: %d\n" , errno); +close (kvm->timerfd); + goto out; + } + + new_value.it_value.tv_sec = now.tv_sec + kvm->display_time; + new_value.it_value.tv_nsec = now.tv_nsec; + new_value.it_interval.tv_sec = kvm->display_time; + new_value.it_interval.tv_nsec =0 ; + +if (timerfd_settime (kvm->timerfd,TFD_TIMER_ABSTIME , + &new_value,NULL ) !=0 ) { +pr_err ("timerfd_settime failed: %d\n" , errno); +close (kvm->timerfd); + goto out; + } + + rc =0 ; +out: +return rc; +} + +static int perf_kvm__handle_timerfd (struct perf_kvm_stat *kvm) +{ +uint64_t c; +int rc; + + rc =read (kvm->timerfd, &c,sizeof (uint64_t )); +if (rc <0 ) { +if (errno ==EAGAIN ) +return 0 ; + +pr_err ("Failed to read timer fd: %d\n" , errno); +return -1 ; + } + +if (rc !=sizeof (uint64_t )) { +pr_err ("Error reading timer fd - invalid size returned\n" ); +return -1 ; + } + +if (c !=1 ) +pr_debug ("Missed timer beats: %" PRIu64"\n" , c-1 ); + +/* update display */ +sort_result (kvm); +print_result (kvm); + +/* reset counts */ +clear_events_cache_stats (kvm->kvm_events_cache); + kvm->total_count =0 ; + kvm->total_time =0 ; + kvm->lost_events =0 ; + +return 0 ; +} + +static int fd_set_nonblock (int fd) +{ +long arg =0 ; + + arg =fcntl (fd,F_GETFL ); +if (arg <0 ) { +pr_err ("Failed to get current flags for fd %d\n" , fd); +return -1 ; + } + +if (fcntl (fd,F_SETFL , arg |O_NONBLOCK ) <0 ) { +pr_err ("Failed to set non-block option on fd %d\n" , fd); +return -1 ; + } + +return 0 ; +} + +static +int perf_kvm__handle_stdin (struct termios *tc_now,struct termios *tc_save) +{ +int c; + +tcsetattr (0 ,TCSANOW , tc_now); + c =getc (stdin); +tcsetattr (0 ,TCSAFLUSH , tc_save); + +if (c =='q' ) +return 1 ; + +return 0 ; +} + +static int kvm_events_live_report (struct perf_kvm_stat *kvm) +{ +struct pollfd *pollfds =NULL ; +int nr_fds, ret, err = -EINVAL ; +struct termios tc, save; + +/* live flag must be set first */ + kvm->live = true; + + ret =cpu_isa_config (kvm); +if (ret <0 ) +return ret; + +if (!verify_vcpu (kvm->trace_vcpu) || + !select_key (kvm) || + !register_kvm_events_ops (kvm)) { + goto out; + } + +init_kvm_event_record (kvm); + +tcgetattr (0 , &save); + tc = save; + tc.c_lflag &= ~(ICANON |ECHO ); + tc.c_cc[VMIN ] =0 ; + tc.c_cc[VTIME ] =0 ; + +signal (SIGINT , sig_handler); +signal (SIGTERM , sig_handler); + +/* copy pollfds -- need to add timerfd and stdin */ + nr_fds = kvm->evlist->nr_fds; + pollfds =zalloc (sizeof (struct pollfd ) * (nr_fds +2 )); +if (!pollfds) { + err = -ENOMEM ; + goto out; + } +memcpy (pollfds, kvm->evlist->pollfd, +sizeof (struct pollfd ) * kvm->evlist->nr_fds); + +/* add timer fd */ +if (perf_kvm__timerfd_create (kvm) <0 ) { + err =-1 ; + goto out; + } + + pollfds[nr_fds].fd = kvm->timerfd; + pollfds[nr_fds].events =POLLIN ; + nr_fds++; + + pollfds[nr_fds].fd =fileno (stdin); + pollfds[nr_fds].events =POLLIN ; + nr_fds++; +if (fd_set_nonblock (fileno (stdin)) !=0 ) + goto out; + +/* everything is good - enable the events and process */ +perf_evlist__enable (kvm->evlist); + +while (!done) { +int rc; + + rc =perf_kvm__mmap_read (kvm); +if (rc <0 ) +break ; + + err =perf_kvm__handle_timerfd (kvm); +if (err) + goto out; + + done =perf_kvm__handle_stdin (&tc, &save); + +if (!rc && !done) + err =poll (pollfds, nr_fds,100 ); + } + +perf_evlist__disable (kvm->evlist); + +if (err ==0 ) { +sort_result (kvm); +print_result (kvm); + } + +out: +if (kvm->timerfd >=0 ) +close (kvm->timerfd); + +if (pollfds) +free (pollfds); + +return err; +} + +static int perf_kvm__open_counters (struct perf_kvm_stat *kvm) +{ +struct perf_evsel *pos; +struct perf_evlist *evlist = kvm->evlist; +char msg[512 ]; + +perf_evlist__config (evlist, &kvm->opts); + +/* +* Note: exclude_{guest,host} do not apply here. +* This command processes KVM tracepoints from host only +*/ +list_for_each_entry (pos, &evlist->entries, node) { +struct perf_event_attr *attr = &pos->attr; + + attr->sample_type |=PERF_SAMPLE_TID ; + attr->sample_type |=PERF_SAMPLE_TIME ; + attr->sample_type |=PERF_SAMPLE_CPU ; + attr->sample_type |=PERF_SAMPLE_RAW ; + + attr->sample_period =1 ; + + attr->watermark =0 ; + attr->wakeup_events =1000 ; + +/* will enable all once we are ready */ + attr->disabled =1 ; + +try_again: +if (perf_evsel__open (pos, evlist->cpus, evlist->threads) <0 ) { +if (perf_evsel__fallback (pos, errno, msg,sizeof (msg))) { +if (verbose) +ui__warning ("%s\n" , msg); + goto try_again; + } + +perf_evsel__open_strerror (pos, &kvm->opts.target, + errno, msg,sizeof (msg)); +ui__error ("%s\n" , msg); + goto out_err; + } + } + +if (perf_evlist__mmap (evlist, kvm->opts.mmap_pages, false) <0 ) { +ui__error ("Failed to mmap with %d (%s)\n" , + errno,strerror (errno)); + goto out_err; + } + +return 0 ; + +out_err: +return -1 ; }static int read_events (struct perf_kvm_stat *kvm)
@@ -749,30 +1177,13 @@ static int read_events(struct perf_kvm_stat *kvm)* Do not use 'isa' recorded in kvm_exit tracepoint since it is not * traced in the old kernel. */ - ret =get_cpu_isa (kvm->session); - + ret =cpu_isa_config (kvm);if (ret <0 )return ret; -if (ret ==1 ) { - kvm->exit_reasons = vmx_exit_reasons; - kvm->exit_reasons_size =ARRAY_SIZE (vmx_exit_reasons); - kvm->exit_reasons_isa ="VMX" ; - } -return perf_session__process_events (kvm->session, &kvm->tool); } -static bool verify_vcpu (int vcpu) -{ -if (vcpu !=-1 && vcpu <0 ) { -pr_err ("Invalid vcpu:%d.\n" , vcpu); -return false; - } - -return true; -} -static int kvm_events_report_vcpu (struct perf_kvm_stat *kvm) {int ret = -EINVAL ;
@@ -886,6 +1297,148 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)return kvm_events_report_vcpu (kvm); } +static int kvm_events_live (struct perf_kvm_stat *kvm, +int argc,const char **argv) +{ +char errbuf[BUFSIZ ]; +int err; +const struct option live_options[] = { +OPT_STRING ('p' ,"pid" , &kvm->opts.target.pid,"pid" , +"record events on existing process id" ), +OPT_STRING ('t' ,"tid" , &kvm->opts.target.tid,"tid" , +"record events on existing thread id" ), +OPT_STRING ('C' ,"cpu" , &kvm->opts.target.cpu_list,"cpu" , +"list of host cpus to monitor" ), +OPT_UINTEGER ('m' ,"mmap-pages" , &kvm->opts.mmap_pages, +"number of mmap data pages" ), +OPT_INCR ('v' ,"verbose" , &verbose, +"be more verbose (show counter open errors, etc)" ), +OPT_BOOLEAN ('a' ,"all-cpus" , &kvm->opts.target.system_wide, +"system-wide collection from all CPUs" ), +OPT_UINTEGER ('d' ,"display" , &kvm->display_time, +"time in seconds between display updates" ), +OPT_STRING (0 ,"event" , &kvm->report_event,"report event" , +"event for reporting: vmexit, mmio, ioport" ), +OPT_INTEGER (0 ,"vcpu" , &kvm->trace_vcpu, +"vcpu id to report" ), +OPT_STRING ('k' ,"key" , &kvm->sort_key,"sort-key" , +"key for sorting: sample(sort by samples number)" +" time (sort by avg time)" ), +OPT_END () + }; +const char *const live_usage[] = { +"perf kvm stat live [<options>]" , +NULL + }; + + +/* event handling */ + kvm->tool.sample = process_sample_event; + kvm->tool.comm = perf_event__process_comm; + kvm->tool.exit = perf_event__process_exit; + kvm->tool.fork = perf_event__process_fork; + kvm->tool.lost = process_lost_event; + kvm->tool.ordered_samples = true; +perf_tool__fill_defaults (&kvm->tool); + +/* set defaults */ + kvm->display_time =1 ; + kvm->opts.user_interval =1 ; + kvm->opts.mmap_pages =512 ; + kvm->opts.target.uses_mmap = true; + kvm->opts.target.uid_str =NULL ; + kvm->opts.target.uid =UINT_MAX ; + +symbol__init (); +disable_buildid_cache (); + + use_browser =0 ; +setup_browser (false); + +if (argc) { + argc =parse_options (argc, argv, live_options, + live_usage,0 ); +if (argc) +usage_with_options (live_usage, live_options); + } + +/* +* target related setups +*/ + err =perf_target__validate (&kvm->opts.target); +if (err) { +perf_target__strerror (&kvm->opts.target, err, errbuf,BUFSIZ ); +ui__warning ("%s" , errbuf); + } + +if (perf_target__none (&kvm->opts.target)) + kvm->opts.target.system_wide = true; + + +/* +* generate the event list +*/ + kvm->evlist =perf_evlist__new (); +if (kvm->evlist ==NULL ) +return -ENOMEM ; + + err =perf_evlist__add_tracepoints (kvm->evlist, + kvm_events_tp, +ARRAY_SIZE (kvm_events_tp)); +if (err !=0 ) + goto out; + + symbol_conf.nr_events = kvm->evlist->nr_entries; + +if (perf_evlist__create_maps (kvm->evlist, &kvm->opts.target) <0 ) +usage_with_options (live_usage, live_options); + +/* +* perf session +*/ + kvm->session =perf_session__new (NULL ,O_WRONLY , false, false, &kvm->tool); +if (kvm->session ==NULL ) { + err = -ENOMEM ; + goto out; + } + kvm->session->evlist = kvm->evlist; +perf_session__set_id_hdr_size (kvm->session); + +/* +* need to get pevent initialized +*/ + err =perf_evlist__trace_init (kvm->evlist, kvm->session); +if (err !=0 ) + goto out; + +if (perf_target__has_task (&kvm->opts.target)) +perf_event__synthesize_thread_map (&kvm->tool, + kvm->evlist->threads, + perf_event__process, + &kvm->session->machines.host); +else +perf_event__synthesize_threads (&kvm->tool, perf_event__process, + &kvm->session->machines.host); + + + err =perf_kvm__open_counters (kvm); +if (err) + goto out; + + err =kvm_events_live_report (kvm); + +out: +exit_browser (0 ); + +if (kvm->session) +perf_session__delete (kvm->session); + kvm->session =NULL ; +perf_evlist__delete_maps (kvm->evlist); +perf_evlist__delete (kvm->evlist); + +return err; +} +static void print_kvm_stat_usage (void ) {printf ("Usage: perf kvm stat <command>\n\n" );
@@ -893,6 +1446,7 @@ static void print_kvm_stat_usage(void)printf ("# Available commands:\n" );printf ("\trecord: record kvm events\n" );printf ("\treport: report statistical data of kvm events\n" ); +printf ("\tlive: live reporting of statistical data of kvm events\n" );printf ("\nOtherwise, it is the alias of 'perf stat':\n" ); }
@@ -922,6 +1476,9 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)if (!strncmp (argv[1 ],"rep" ,3 ))return kvm_events_report (&kvm, argc -1 , argv +1 ); +if (!strncmp (argv[1 ],"live" ,4 )) +return kvm_events_live (&kvm, argc -1 , argv +1 ); + perf_stat:return cmd_stat (argc, argv,NULL ); }
Signature · 1 line
1.7.10.1
Namhyung Kim
maintainerRe: [PATCH 10/13] perf kvm: add live mode
On Wed, 8 May 2013 22:31:46 -0600, David Ahern wrote:
[SNIP]
Quoted 15 lines
tools/perf/builtin-kvm.c +15
-0+static int perf_kvm__timerfd_create (struct perf_kvm_stat *kvm) +{ +struct itimerspec new_value; +struct timespec now; +int rc =-1 ; + + kvm->timerfd =timerfd_create (CLOCK_MONOTONIC ,TFD_NONBLOCK ); +if (kvm->timerfd <0 ) { +pr_err ("timerfd_create failed\n" ); + goto out; + } + +if (clock_gettime (CLOCK_MONOTONIC , &now) !=0 ) { +pr_err ("clock_gettime failed: %d\n" , errno); +close (kvm->timerfd);
tools/perf/builtin-kvm.c static int get_cpu_isa(struct perf_session *session) · line 928
Quoted 10 lines
tools/perf/builtin-kvm.c +10
-0+ goto out; + } + + new_value.it_value.tv_sec = now.tv_sec + kvm->display_time; + new_value.it_value.tv_nsec = now.tv_nsec; + new_value.it_interval.tv_sec = kvm->display_time; + new_value.it_interval.tv_nsec =0 ; + +if (timerfd_settime (kvm->timerfd,TFD_TIMER_ABSTIME , + &new_value,NULL ) !=0 ) {
Looks like no need to use ABSTIME.
Thanks,
Namhyung
Re: [PATCH 10/13] perf kvm: add live mode
Quoted 21 lines · Namhyung Kim
On Wed, 8 May 2013 22:31:46 -0600, David Ahern wrote:
[SNIP]Quoted 19 lines
tools/perf/builtin-kvm.c +19
-0+static int perf_kvm__timerfd_create (struct perf_kvm_stat *kvm) +{ +struct itimerspec new_value; +struct timespec now; +int rc =-1 ; + + kvm->timerfd =timerfd_create (CLOCK_MONOTONIC ,TFD_NONBLOCK ); +if (kvm->timerfd <0 ) { +pr_err ("timerfd_create failed\n" ); + goto out; + } + +if (clock_gettime (CLOCK_MONOTONIC , &now) !=0 ) { +pr_err ("clock_gettime failed: %d\n" , errno); +close (kvm->timerfd); + goto out; + } + + new_value.it_value.tv_sec = now.tv_sec + kvm->display_time;
Quoted 8 lines
tools/perf/builtin-kvm.c static int get_cpu_isa(struct perf_session *session) · line 928
Quoted 6 lines
tools/perf/builtin-kvm.c +6
-0+ new_value.it_value.tv_nsec = now.tv_nsec; + new_value.it_interval.tv_sec = kvm->display_time; + new_value.it_interval.tv_nsec =0 ; + +if (timerfd_settime (kvm->timerfd,TFD_TIMER_ABSTIME , + &new_value,NULL ) !=0 ) {Looks like no need to use ABSTIME.
hmmm.... I did that for a reason. I forget why now. Let me poke around with it and see if I can remember.
David
Re: [PATCH 10/13] perf kvm: add live mode
In reply to David AhernQuoted 10 lines · David Ahern
perf kvm stat currently requires back to back record and report commands to see stats. e.g,.
perf kvm stat record -p $pid -- sleep 1
perf kvm stat reportThis is inconvenvient for on box monitoring of a VM. This patch introduces a 'live' mode that in effect combines the record plus report into one command. e.g., to monitor a single VM:
Quoted 8 lines
perf kvm stat live -p $pid
or all VMs:
perf kvm stat live
Same stats options for the record+report path work with the live mode. Display rate defaults to 1 second and can be changed using the -d option.
Nice!
1)
Regarding the basic syntax - is the 'perf stat kvm' command already used up? If not then it might make sense to alias 'perf kvm stat live' to 'perf kvm stat', making it really easy to use:
perf kvm stat
perf kvm stat -p <pid>
etc. I'd expect most 'perf kvm stat' users to utilize this syntax - so it makes sense to make 'live' the default and main command.
2)
Another suggestion: it would be nice to allow a "--repeat <n>" option as well, for a limited number of iterations - similar to what the 'top' tool allows:
top -b -d <delay> -n <iterations>
--repeat 0 means infinite repeats, --repeat 1 means a single step.
3)
It might make sense to create 'perf kvm stat top' which is a small variation to 'perf kvm stat live': it outputs a perf stat output per second, but also outputs a clear-screen sequence before the output.
To keep it simple you could do this with plain console text output, not libslang, the C code to generate a clear screen sequence can be generated via this shell oneliner:
echo 'prinf("'$(clear)'");' > clearscreen.cThis way people could see constantly updating top-alike KVM statistics.
Thanks,
Ingo
Re: [PATCH 10/13] perf kvm: add live mode
Quoted 11 lines · Ingo Molnar
1)
Regarding the basic syntax - is the 'perf stat kvm' command already used up? If not then it might make sense to alias 'perf kvm stat live' to 'perf kvm stat', making it really easy to use:
perf kvm stat
perf kvm stat -p <pid>etc. I'd expect most 'perf kvm stat' users to utilize this syntax - so it makes sense to make 'live' the default and main command.
The default is for 'perf kvm stat' to call cmd_stat (i.e, perf kvm stat == perf stat with perf_guest flag set to 1).
Quoted 10 lines
2)
Another suggestion: it would be nice to allow a "--repeat <n>" option as well, for a limited number of iterations - similar to what the 'top' tool allows:
top -b -d <delay> -n <iterations>
--repeat 0 means infinite repeats, --repeat 1 means a single step.
Missed that option in perf-top. Let me take a look at it.
Quoted 6 lines
3)
It might make sense to create 'perf kvm stat top' which is a small variation to 'perf kvm stat live': it outputs a perf stat output per second, but also outputs a clear-screen sequence before the output.
Quoted 7 lines
To keep it simple you could do this with plain console text output, not libslang, the C code to generate a clear screen sequence can be generated via this shell oneliner:
echo 'prinf("'$(clear)'");' > clearscreen.cThis way people could see constantly updating top-alike KVM statistics.
Ok, once the basic live command is pulled into Arnaldo's tree I can look at variations like these last 2 suggestions.
David
Namhyung Kim
maintainerRe: [PATCH 10/13] perf kvm: add live mode
Hi David,
Quoted 7 lines · David Ahern
Quoted 6 lines · Ingo Molnar
2)
Another suggestion: it would be nice to allow a "--repeat <n>" option as well, for a limited number of iterations - similar to what the 'top' tool allows:
Quoted 5 lines
Quoted 3 lines
top -b -d <delay> -n <iterations>
--repeat 0 means infinite repeats, --repeat 1 means a single step.
Missed that option in perf-top. Let me take a look at it.
What Ingo said was plain "top" command, not the perf-top.
Thanks,
Namhyung
Re: [PATCH 10/13] perf kvm: add live mode
Quoted 10 lines · Namhyung Kim
Hi David,
Quoted 7 lines · David Ahern
Quoted 6 lines · Ingo Molnar
2)
Another suggestion: it would be nice to allow a "--repeat <n>" option as well, for a limited number of iterations - similar to what the 'top' tool allows:
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
top -b -d <delay> -n <iterations>
--repeat 0 means infinite repeats, --repeat 1 means a single step.
Missed that option in perf-top. Let me take a look at it.
What Ingo said was plain "top" command, not the perf-top.
That would explain why I missed that option then. ;-) Funny how your brain can fill in ...
David
Re: [PATCH 10/13] perf kvm: add live mode
In reply to David AhernQuoted 11 lines · David Ahern
Quoted 9 lines
2)
Another suggestion: it would be nice to allow a "--repeat <n>" option as well, for a limited number of iterations - similar to what the 'top' tool allows:
top -b -d <delay> -n <iterations>
--repeat 0 means infinite repeats, --repeat 1 means a single step.
Missed that option in perf-top. Let me take a look at it.
-n and -b is a regular /usr/bin/top feature, not perf-top feature :-)
perf-top has no such option AFAICS - but it could be added there as well. Regular perf-stat has a --repeat option and it's very useful there.
Thanks,
Ingo
Re: [PATCH 10/13] perf kvm: add live mode
In reply to David AhernHi, David,
Xiao Guangrong forward your patch to me two month ago, it is originally at https://github.com/dsahern/linux.git.
However, those patches were based on an old linux tree, they can't be applied to current linux tree, so I try to fix the conflicts on the latest Arnaldo Carvalho de Melo tree, and I finished this work Yesterday!
So, I'm sorry that I didn't inform you earlier, and we do the repetitive work.
In your original patch, you hope the live mode can change display time dynamically. Fortunately, I implement this function and I will send the patch to you as soon as possible, please wait. :)
Thanks
Runzhen Wang
Re: [PATCH 10/13] perf kvm: add live mode
Quoted 8 lines · Runzhen
Hi, David,
Xiao Guangrong forward your patch to me two month ago, it is originally at https://github.com/dsahern/linux.git.
However, those patches were based on an old linux tree, they can't be applied to current linux tree, so I try to fix the conflicts on the latest Arnaldo Carvalho de Melo tree, and I finished this work Yesterday!
I update the patches as kernel versions are released (not rc's though) and push to the github site. This round uses the consolidated open counters code that Arnaldo did back in December. I was distracted with other work and missed what he had done until recently. I need to address comments and resubmit. Should be able to get this into Arnaldo's tree soon and then into v3.11. The patches on github can be used for older versions.
Quoted 7 lines
So, I'm sorry that I didn't inform you earlier, and we do the repetitive work.
In your original patch, you hope the live mode can change display time dynamically. Fortunately, I implement this function and I will send the patch to you as soon as possible, please wait. :)
Awesome, look forward to seeing it.
David
PATCH 11/13 perf kvm: add min and max stats to display
In reply to David Ahern--- tools/perf/builtin-kvm.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
tools/perf/builtin-kvm.c +18 -3
@@ -337,14 +337,19 @@ static void clear_events_cache_stats(struct list_head *kvm_events_cache)struct list_head *head;struct kvm_event *event;unsigned int i; +int j;for (i =0 ; i <EVENTS_CACHE_SIZE ; i++) { head = &kvm_events_cache[i];list_for_each_entry (event, head, hash_entry) {/* reset stats for event */ -memset (&event->total,0 ,sizeof (event->total)); -memset (event->vcpu,0 , - event->max_vcpu *sizeof (*event->vcpu)); + event->total.time =0 ; +init_stats (&event->total.stats); + +for (j =0 ; j < event->max_vcpu; ++j) { + event->vcpu[j].time =0 ; +init_stats (&event->vcpu[j].stats); + } } } }
@@ -718,6 +723,7 @@ static void print_result(struct perf_kvm_stat *kvm)char decode[20 ];struct kvm_event *event;int vcpu = kvm->trace_vcpu; +struct kvm_event_stats *kvm_stats;if (kvm->live) {puts (CONSOLE_CLEAR );
@@ -731,6 +737,8 @@ static void print_result(struct perf_kvm_stat *kvm)pr_info ("%9s " ,"Samples%" );pr_info ("%9s " ,"Time%" ); +pr_info ("%10s " ,"Min Time" ); +pr_info ("%10s " ,"Max Time" );pr_info ("%16s " ,"Avg time" );pr_info ("\n\n" );
@@ -740,11 +748,18 @@ static void print_result(struct perf_kvm_stat *kvm) ecount =get_event_count (event, vcpu); etime =get_event_time (event, vcpu); +if (vcpu ==-1 ) + kvm_stats = &event->total; +else + kvm_stats = &event->vcpu[vcpu]; + kvm->events_ops->decode_key (kvm, &event->key, decode);pr_info ("%20s " , 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 ); +pr_info ("%8" PRIu64"us " , kvm_stats->stats.min /1000 ); +pr_info ("%8" PRIu64"us " , kvm_stats->stats.max /1000 );pr_info ("%9.2fus ( +-%7.2f%% )" , (double )etime / ecount/1e3 ,kvm_event_rel_stddev (vcpu, event));pr_info ("\n" );
Signature · 1 line
1.7.10.1
PATCH 12/13 perf kvm: option to print events that exceed a threshold
In reply to David AhernThis is useful to spot high latency blips.
--- tools/perf/builtin-kvm.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
tools/perf/builtin-kvm.c +20 -4
@@ -106,6 +106,7 @@ struct perf_kvm_stat {u64 total_time;u64 total_count;u64 lost_events; +u64 threshold;struct rb_root result;
@@ -470,7 +471,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,static bool handle_end_event (struct perf_kvm_stat *kvm,struct vcpu_event_record *vcpu_record,struct event_key *key, -u64 timestamp) +struct perf_sample *sample) {struct kvm_event *event;u64 time_begin, time_diff;
@@ -507,12 +508,24 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, vcpu_record->start_time =0 ;/* seems to happen once in a while during live mode */ -if (timestamp < time_begin) { +if (sample->time < time_begin) {pr_debug ("End time before begin time; skipping event.\n" );return true; } - time_diff = timestamp - time_begin; + time_diff = sample->time - time_begin; + +if (kvm->threshold && time_diff > kvm->threshold) { +char decode[32 ]; + + kvm->events_ops->decode_key (kvm, &event->key, decode); +if (strcmp (decode,"HLT" )) { +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 ); + } + } +return update_kvm_event (event, vcpu, time_diff); }
@@ -559,7 +572,7 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,return handle_begin_event (kvm, vcpu_record, &key, sample->time);if (kvm->events_ops->is_end_event (evsel, sample, &key)) -return handle_end_event (kvm, vcpu_record, &key, sample->time); +return handle_end_event (kvm, vcpu_record, &key, sample);return true; }
@@ -1339,6 +1352,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,OPT_STRING ('k' ,"key" , &kvm->sort_key,"sort-key" ,"key for sorting: sample(sort by samples number)" " time (sort by avg time)" ), +OPT_U64 ('T' ,"threshold" , &kvm->threshold, +"show events that take longer than threshold usecs" ),OPT_END () }; const char * const live_usage[] = {
@@ -1369,6 +1384,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, use_browser =0 ;setup_browser (false); + kvm->threshold *=1000 ;/* convert usec to nsec */ if (argc) { argc = parse_options(argc, argv, live_options,
Signature · 1 line
1.7.10.1
PATCH 13/13 perf kvm: debug for missing vmexit/vmentry event
In reply to David AhernExpected to have missing events for each vcpu when perf is started. After that should not have missing events.
--- tools/perf/builtin-kvm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
tools/perf/builtin-kvm.c +13 -2
@@ -568,11 +568,22 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, (kvm->trace_vcpu != vcpu_record->vcpu_id))return true; -if (kvm->events_ops->is_begin_event (evsel, sample, &key)) +if (kvm->events_ops->is_begin_event (evsel, sample, &key)) { +if (vcpu_record->start_time) { +pr_debug ("consecutive begin events (%s) for pid %d, vcpu %d\n" , + evsel->name, sample->pid, vcpu_record->vcpu_id); + }return handle_begin_event (kvm, vcpu_record, &key, sample->time); + } + -if (kvm->events_ops->is_end_event (evsel, sample, &key)) +if (kvm->events_ops->is_end_event (evsel, sample, &key)) { +if (vcpu_record->start_time ==0 ) { +pr_debug ("consecutive end events (%s) for pid %d, vcpu %d\n" , + evsel->name, sample->pid, vcpu_record->vcpu_id); + }return handle_end_event (kvm, vcpu_record, &key, sample); + }return true; }
Signature · 1 line
1.7.10.1
CC kvm list.
Quoted 3 lines · David Ahern
With the consolidation of the open counters code in December 2012 (late to the party figuring that out) I think all of the past comments on the live mode for perf-kvm have been resolved.
Great work, David! I am playing it and glad to see it works fine. Will review the patches later.
Quoted 10 lines · Xiao Guangrong
CC kvm list.
Quoted 3 lines · David Ahern
With the consolidation of the open counters code in December 2012 (late to the party figuring that out) I think all of the past comments on the live mode for perf-kvm have been resolved.
Great work, David! I am playing it and glad to see it works fine. Will review the patches later.
Looks very useful indeed!
--
Gleb.