* [PATCH 0 of 2] xenalyze: decode new hypercall trace records (v2) @ 2012-10-04 12:28 David Vrabel 2012-10-04 12:28 ` [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records David Vrabel 2012-10-04 12:28 ` [PATCH 2 of 2] xenalyze: decode PV_HYPERCALL_SUBCALL events David Vrabel 0 siblings, 2 replies; 4+ messages in thread From: David Vrabel @ 2012-10-04 12:28 UTC (permalink / raw) To: xen-devel; +Cc: David Vrabel, George Dunlap This series allows xenalyze to decode the new PV_HYPERCALL_V2 and PV_HYPERCALL_SUBCALL trace records being proposed for Xen 4.3. Changes since v1: - pv_hypercall_gather_args() instead of pv_hypercall_arg(). - Refactor *_cmd_to_str. David ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records 2012-10-04 12:28 [PATCH 0 of 2] xenalyze: decode new hypercall trace records (v2) David Vrabel @ 2012-10-04 12:28 ` David Vrabel 2012-10-10 13:26 ` George Dunlap 2012-10-04 12:28 ` [PATCH 2 of 2] xenalyze: decode PV_HYPERCALL_SUBCALL events David Vrabel 1 sibling, 1 reply; 4+ messages in thread From: David Vrabel @ 2012-10-04 12:28 UTC (permalink / raw) To: xen-devel; +Cc: David Vrabel, George Dunlap Newer version of Xen produce TRC_PV_HYPERCALL_V2 records instead of the older TRC_PV_HYPERCALL format. This updated format doesn't included the IP but it does include select hypercall arguments. Signed-off-by: David Vrabel <david.vrabel@citrix.com> diff --git a/analyze.h b/analyze.h --- a/analyze.h +++ b/analyze.h @@ -3,6 +3,8 @@ #include <stdint.h> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + #define TRC_GEN_MAIN 0 #define TRC_SCHED_MAIN 1 #define TRC_DOM0OP_MAIN 2 diff --git a/pv.h b/pv.h new file mode 100644 --- /dev/null +++ b/pv.h @@ -0,0 +1,41 @@ +/* + * PV event decoding. + * + * Copyright (C) 2012 Citrix Systems R&D Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#ifndef __PV_H + +#include "analyze.h" +#include "trace.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARG_MISSING 0x0 +#define ARG_32BIT 0x1 +#define ARG_64BIT 0x2 + +#define MMU_UPDATE_PREEMPTED (~(~0U>>1)) + +static inline uint32_t pv_hypercall_op(const struct record_info *ri) +{ + return ri->d[0] & ~TRC_PV_HYPERCALL_V2_ARG_MASK; +} + +static inline int pv_hypercall_arg_present(const struct record_info *ri, int arg) +{ + return (ri->d[0] >> (20 + 2*arg)) & 0x3; +} + +void pv_hypercall_gather_args(const struct record_info *ri, uint64_t *args); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -32,6 +32,7 @@ #include "trace.h" #include "analyze.h" #include "mread.h" +#include "pv.h" #include <errno.h> #include <strings.h> #include <string.h> @@ -1485,6 +1486,7 @@ enum { PV_GDT_LDT_MAPPING_FAULT, PV_PTWR_EMULATION, PV_PTWR_EMULATION_PAE, + PV_HYPERCALL_V2 = 13, PV_MAX }; @@ -1499,7 +1501,9 @@ char *pv_name[PV_MAX] = { [PV_PAGING_FIXUP]="paging fixup", [PV_GDT_LDT_MAPPING_FAULT]="gdt/ldt mapping fault", [PV_PTWR_EMULATION]="ptwr", - [PV_PTWR_EMULATION_PAE]="ptwr(pae)" + [PV_PTWR_EMULATION_PAE]="ptwr(pae)", + [PV_HYPERCALL_V2]="hypercall", + [PV_HYPERCALL_SUBCALL]="hypercall (subcall)", }; #define PV_HYPERCALL_MAX 56 @@ -6500,10 +6504,20 @@ void pv_summary(struct pv_data *pv) { printf("PV events:\n"); for(i=0; i<PV_MAX; i++) { - if(pv->count[i]) - printf(" %s %d\n", pv_name[i], pv->count[i]); + int count; + + count = pv->count[i]; + if (i == PV_HYPERCALL_V2) + count += pv->count[PV_HYPERCALL_SUBCALL]; + + if (count == 0) + continue; + + printf(" %s %d\n", pv_name[i], count); + switch(i) { case PV_HYPERCALL: + case PV_HYPERCALL_V2: for(j=0; j<PV_HYPERCALL_MAX; j++) { if(pv->hypercall_count[j]) printf(" %-29s[%2d]: %6d\n", @@ -6523,6 +6537,145 @@ void pv_summary(struct pv_data *pv) { } } +static const char *grant_table_op_str[] = { + "map_grant_ref", "unmap_grant_ref", "setup_table", "dump_table", + "transfer", "copy", "query_size", "unmap_and_replace", + "set_version", "get_status_frames", "get_version", "swap_grant_ref", +}; + +static const char *vcpu_op_str[] = { + "initialise", "up", "down", "is_up", "get_runstate_info", + "register_runstate_memory_area", "set_periodic_timer", + "stop_periodic_timer", "set_singleshot_timer", "stop_singleshot_timer", + "register_vcpu_info", "send_nmi", "get_physid", + "register_vcpu_time_memory_area", +}; + +static const char *sched_op_str[] = { + "yield", "block", "shutdown", "poll", "remote_shutdown", "shutdown_code", + "watchdog", +}; + +static const char *cmd_to_str(const char *strings[], size_t n, uint32_t cmd) +{ + static char buf[32]; + + if (cmd < n) + return strings[cmd]; + + snprintf(buf, sizeof(buf), "unknown (%d)", cmd); + return buf; +} + +#define CMD_TO_STR(op) \ + static const char * op ## _to_str(uint32_t cmd) { \ + return cmd_to_str(op ## _str, ARRAY_SIZE(op ## _str), cmd); \ + } + +CMD_TO_STR(grant_table_op); +CMD_TO_STR(vcpu_op); +CMD_TO_STR(sched_op); + +void pv_hypercall_gather_args(const struct record_info *ri, uint64_t *args) +{ + int i, word; + + /* Missing arguments are zeroed. */ + memset(args, 0, 6 * sizeof(uint64_t)); + + for (i = 0, word = 1; i < 6 && word < ri->extra_words; i++) { + int present = pv_hypercall_arg_present(ri, i); + + switch (present) { + case ARG_32BIT: + args[i] = ri->d[word]; + break; + case ARG_64BIT: + args[i] = ((uint64_t)ri->d[word + 1] << 32) | ri->d[word]; + break; + } + + /* Skip over any words for this argument. */ + word += present; + } +} + +static void pv_hypercall_print_args(const struct record_info *ri) +{ + int i, word; + + for (i = 0, word = 1; i < 6 && word < ri->extra_words; i++) { + int present = pv_hypercall_arg_present(ri, i); + + switch (present) { + case ARG_MISSING: + printf(" ??"); + break; + case ARG_32BIT: + printf(" %08x", ri->d[word]); + break; + case ARG_64BIT: + printf(" %016"PRIu64"", ((uint64_t)ri->d[word + 1] << 32) | ri->d[word]); + break; + } + + word += present; + } +} + +void pv_hypercall_v2_process(struct record_info *ri, struct pv_data *pv) +{ + int op = pv_hypercall_op(ri); + + if(opt.summary_info) { + if(op < PV_HYPERCALL_MAX) + pv->hypercall_count[op]++; + } + + if(opt.dump_all) { + uint64_t args[6]; + + if(op < HYPERCALL_MAX) + printf(" %s hypercall %2x (%s)", + ri->dump_header, op, hypercall_name[op]); + else + printf(" %s hypercall %2x", + ri->dump_header, op); + + switch(op) { + case HYPERCALL_mmu_update: + pv_hypercall_gather_args(ri, args); + printf(" %d updates%s", (uint32_t)args[1] & ~MMU_UPDATE_PREEMPTED, + (args[1] & MMU_UPDATE_PREEMPTED) ? " (preempted)" : ""); + break; + case HYPERCALL_multicall: + pv_hypercall_gather_args(ri, args); + printf(" %d calls", (uint32_t)args[1]); + break; + case HYPERCALL_grant_table_op: + pv_hypercall_gather_args(ri, args); + printf(" %s %d ops", grant_table_op_to_str(args[0]), (uint32_t)args[2]); + break; + case HYPERCALL_vcpu_op: + pv_hypercall_gather_args(ri, args); + printf(" %s vcpu %d", vcpu_op_to_str(args[0]), (uint32_t)args[1]); + break; + case HYPERCALL_mmuext_op: + pv_hypercall_gather_args(ri, args); + printf(" %d ops", (uint32_t)args[1]); + break; + case HYPERCALL_sched_op: + pv_hypercall_gather_args(ri, args); + printf(" %s", sched_op_to_str(args[0])); + break; + default: + pv_hypercall_print_args(ri); + break; + } + printf("\n"); + } +} + void pv_process(struct pcpu_info *p) { struct record_info *ri = &p->ri; @@ -6555,9 +6708,9 @@ void pv_process(struct pcpu_info *p) case PV_PTWR_EMULATION_PAE: pv_ptwr_emulation_process(ri, pv); break; - case PV_PAGE_FAULT: - //pv_pf_process(ri, pv); - //break; + case PV_HYPERCALL_V2: + pv_hypercall_v2_process(ri, pv); + break; default: pv_generic_process(ri, pv); break; ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records 2012-10-04 12:28 ` [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records David Vrabel @ 2012-10-10 13:26 ` George Dunlap 0 siblings, 0 replies; 4+ messages in thread From: George Dunlap @ 2012-10-10 13:26 UTC (permalink / raw) To: David Vrabel; +Cc: George Dunlap, xen-devel On Thu, Oct 4, 2012 at 1:28 PM, David Vrabel <david.vrabel@citrix.com> wrote: > Newer version of Xen produce TRC_PV_HYPERCALL_V2 records instead of > the older TRC_PV_HYPERCALL format. This updated format doesn't > included the IP but it does include select hypercall arguments. > > Signed-off-by: David Vrabel <david.vrabel@citrix.com> You had a couple of stray SUBCALL things in this patch which cause it to fail compilation; I moved them to the next patch and have committed both patches. Thanks. -George. > > diff --git a/analyze.h b/analyze.h > --- a/analyze.h > +++ b/analyze.h > @@ -3,6 +3,8 @@ > > #include <stdint.h> > > +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) > + > #define TRC_GEN_MAIN 0 > #define TRC_SCHED_MAIN 1 > #define TRC_DOM0OP_MAIN 2 > diff --git a/pv.h b/pv.h > new file mode 100644 > --- /dev/null > +++ b/pv.h > @@ -0,0 +1,41 @@ > +/* > + * PV event decoding. > + * > + * Copyright (C) 2012 Citrix Systems R&D Ltd. > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + */ > +#ifndef __PV_H > + > +#include "analyze.h" > +#include "trace.h" > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#define ARG_MISSING 0x0 > +#define ARG_32BIT 0x1 > +#define ARG_64BIT 0x2 > + > +#define MMU_UPDATE_PREEMPTED (~(~0U>>1)) > + > +static inline uint32_t pv_hypercall_op(const struct record_info *ri) > +{ > + return ri->d[0] & ~TRC_PV_HYPERCALL_V2_ARG_MASK; > +} > + > +static inline int pv_hypercall_arg_present(const struct record_info *ri, int arg) > +{ > + return (ri->d[0] >> (20 + 2*arg)) & 0x3; > +} > + > +void pv_hypercall_gather_args(const struct record_info *ri, uint64_t *args); > + > +#ifdef __cplusplus > +} /* extern "C" */ > +#endif > + > +#endif > diff --git a/xenalyze.c b/xenalyze.c > --- a/xenalyze.c > +++ b/xenalyze.c > @@ -32,6 +32,7 @@ > #include "trace.h" > #include "analyze.h" > #include "mread.h" > +#include "pv.h" > #include <errno.h> > #include <strings.h> > #include <string.h> > @@ -1485,6 +1486,7 @@ enum { > PV_GDT_LDT_MAPPING_FAULT, > PV_PTWR_EMULATION, > PV_PTWR_EMULATION_PAE, > + PV_HYPERCALL_V2 = 13, > PV_MAX > }; > > @@ -1499,7 +1501,9 @@ char *pv_name[PV_MAX] = { > [PV_PAGING_FIXUP]="paging fixup", > [PV_GDT_LDT_MAPPING_FAULT]="gdt/ldt mapping fault", > [PV_PTWR_EMULATION]="ptwr", > - [PV_PTWR_EMULATION_PAE]="ptwr(pae)" > + [PV_PTWR_EMULATION_PAE]="ptwr(pae)", > + [PV_HYPERCALL_V2]="hypercall", > + [PV_HYPERCALL_SUBCALL]="hypercall (subcall)", > }; > > #define PV_HYPERCALL_MAX 56 > @@ -6500,10 +6504,20 @@ void pv_summary(struct pv_data *pv) { > > printf("PV events:\n"); > for(i=0; i<PV_MAX; i++) { > - if(pv->count[i]) > - printf(" %s %d\n", pv_name[i], pv->count[i]); > + int count; > + > + count = pv->count[i]; > + if (i == PV_HYPERCALL_V2) > + count += pv->count[PV_HYPERCALL_SUBCALL]; > + > + if (count == 0) > + continue; > + > + printf(" %s %d\n", pv_name[i], count); > + > switch(i) { > case PV_HYPERCALL: > + case PV_HYPERCALL_V2: > for(j=0; j<PV_HYPERCALL_MAX; j++) { > if(pv->hypercall_count[j]) > printf(" %-29s[%2d]: %6d\n", > @@ -6523,6 +6537,145 @@ void pv_summary(struct pv_data *pv) { > } > } > > +static const char *grant_table_op_str[] = { > + "map_grant_ref", "unmap_grant_ref", "setup_table", "dump_table", > + "transfer", "copy", "query_size", "unmap_and_replace", > + "set_version", "get_status_frames", "get_version", "swap_grant_ref", > +}; > + > +static const char *vcpu_op_str[] = { > + "initialise", "up", "down", "is_up", "get_runstate_info", > + "register_runstate_memory_area", "set_periodic_timer", > + "stop_periodic_timer", "set_singleshot_timer", "stop_singleshot_timer", > + "register_vcpu_info", "send_nmi", "get_physid", > + "register_vcpu_time_memory_area", > +}; > + > +static const char *sched_op_str[] = { > + "yield", "block", "shutdown", "poll", "remote_shutdown", "shutdown_code", > + "watchdog", > +}; > + > +static const char *cmd_to_str(const char *strings[], size_t n, uint32_t cmd) > +{ > + static char buf[32]; > + > + if (cmd < n) > + return strings[cmd]; > + > + snprintf(buf, sizeof(buf), "unknown (%d)", cmd); > + return buf; > +} > + > +#define CMD_TO_STR(op) \ > + static const char * op ## _to_str(uint32_t cmd) { \ > + return cmd_to_str(op ## _str, ARRAY_SIZE(op ## _str), cmd); \ > + } > + > +CMD_TO_STR(grant_table_op); > +CMD_TO_STR(vcpu_op); > +CMD_TO_STR(sched_op); > + > +void pv_hypercall_gather_args(const struct record_info *ri, uint64_t *args) > +{ > + int i, word; > + > + /* Missing arguments are zeroed. */ > + memset(args, 0, 6 * sizeof(uint64_t)); > + > + for (i = 0, word = 1; i < 6 && word < ri->extra_words; i++) { > + int present = pv_hypercall_arg_present(ri, i); > + > + switch (present) { > + case ARG_32BIT: > + args[i] = ri->d[word]; > + break; > + case ARG_64BIT: > + args[i] = ((uint64_t)ri->d[word + 1] << 32) | ri->d[word]; > + break; > + } > + > + /* Skip over any words for this argument. */ > + word += present; > + } > +} > + > +static void pv_hypercall_print_args(const struct record_info *ri) > +{ > + int i, word; > + > + for (i = 0, word = 1; i < 6 && word < ri->extra_words; i++) { > + int present = pv_hypercall_arg_present(ri, i); > + > + switch (present) { > + case ARG_MISSING: > + printf(" ??"); > + break; > + case ARG_32BIT: > + printf(" %08x", ri->d[word]); > + break; > + case ARG_64BIT: > + printf(" %016"PRIu64"", ((uint64_t)ri->d[word + 1] << 32) | ri->d[word]); > + break; > + } > + > + word += present; > + } > +} > + > +void pv_hypercall_v2_process(struct record_info *ri, struct pv_data *pv) > +{ > + int op = pv_hypercall_op(ri); > + > + if(opt.summary_info) { > + if(op < PV_HYPERCALL_MAX) > + pv->hypercall_count[op]++; > + } > + > + if(opt.dump_all) { > + uint64_t args[6]; > + > + if(op < HYPERCALL_MAX) > + printf(" %s hypercall %2x (%s)", > + ri->dump_header, op, hypercall_name[op]); > + else > + printf(" %s hypercall %2x", > + ri->dump_header, op); > + > + switch(op) { > + case HYPERCALL_mmu_update: > + pv_hypercall_gather_args(ri, args); > + printf(" %d updates%s", (uint32_t)args[1] & ~MMU_UPDATE_PREEMPTED, > + (args[1] & MMU_UPDATE_PREEMPTED) ? " (preempted)" : ""); > + break; > + case HYPERCALL_multicall: > + pv_hypercall_gather_args(ri, args); > + printf(" %d calls", (uint32_t)args[1]); > + break; > + case HYPERCALL_grant_table_op: > + pv_hypercall_gather_args(ri, args); > + printf(" %s %d ops", grant_table_op_to_str(args[0]), (uint32_t)args[2]); > + break; > + case HYPERCALL_vcpu_op: > + pv_hypercall_gather_args(ri, args); > + printf(" %s vcpu %d", vcpu_op_to_str(args[0]), (uint32_t)args[1]); > + break; > + case HYPERCALL_mmuext_op: > + pv_hypercall_gather_args(ri, args); > + printf(" %d ops", (uint32_t)args[1]); > + break; > + case HYPERCALL_sched_op: > + pv_hypercall_gather_args(ri, args); > + printf(" %s", sched_op_to_str(args[0])); > + break; > + default: > + pv_hypercall_print_args(ri); > + break; > + } > + printf("\n"); > + } > +} > + > void pv_process(struct pcpu_info *p) > { > struct record_info *ri = &p->ri; > @@ -6555,9 +6708,9 @@ void pv_process(struct pcpu_info *p) > case PV_PTWR_EMULATION_PAE: > pv_ptwr_emulation_process(ri, pv); > break; > - case PV_PAGE_FAULT: > - //pv_pf_process(ri, pv); > - //break; > + case PV_HYPERCALL_V2: > + pv_hypercall_v2_process(ri, pv); > + break; > default: > pv_generic_process(ri, pv); > break; > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2 of 2] xenalyze: decode PV_HYPERCALL_SUBCALL events 2012-10-04 12:28 [PATCH 0 of 2] xenalyze: decode new hypercall trace records (v2) David Vrabel 2012-10-04 12:28 ` [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records David Vrabel @ 2012-10-04 12:28 ` David Vrabel 1 sibling, 0 replies; 4+ messages in thread From: David Vrabel @ 2012-10-04 12:28 UTC (permalink / raw) To: xen-devel; +Cc: David Vrabel, George Dunlap Decode the PV_HYPERCALL_SUBCALL events which are used for calls within a multicall hypercall. They are indented so its easier to see which multicall they were part of. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Acked-by: George Dunlap <george.dunlap@citrix.com> diff --git a/xenalyze.c b/xenalyze.c --- a/xenalyze.c +++ b/xenalyze.c @@ -1487,6 +1487,7 @@ enum { PV_PTWR_EMULATION, PV_PTWR_EMULATION_PAE, PV_HYPERCALL_V2 = 13, + PV_HYPERCALL_SUBCALL = 14, PV_MAX }; @@ -6623,7 +6624,8 @@ static void pv_hypercall_print_args(cons } } -void pv_hypercall_v2_process(struct record_info *ri, struct pv_data *pv) +void pv_hypercall_v2_process(struct record_info *ri, struct pv_data *pv, + const char *indent) { int op = pv_hypercall_op(ri); @@ -6636,11 +6638,11 @@ void pv_hypercall_v2_process(struct reco uint64_t args[6]; if(op < HYPERCALL_MAX) - printf(" %s hypercall %2x (%s)", - ri->dump_header, op, hypercall_name[op]); + printf(" %s%s hypercall %2x (%s)", + ri->dump_header, indent, op, hypercall_name[op]); else - printf(" %s hypercall %2x", - ri->dump_header, op); + printf(" %s%s hypercall %2x", + ri->dump_header, indent, op); switch(op) { case HYPERCALL_mmu_update: @@ -6709,7 +6711,10 @@ void pv_process(struct pcpu_info *p) pv_ptwr_emulation_process(ri, pv); break; case PV_HYPERCALL_V2: - pv_hypercall_v2_process(ri, pv); + pv_hypercall_v2_process(ri, pv, ""); + break; + case PV_HYPERCALL_SUBCALL: + pv_hypercall_v2_process(ri, pv, " "); break; default: pv_generic_process(ri, pv); ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-10-10 13:26 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-10-04 12:28 [PATCH 0 of 2] xenalyze: decode new hypercall trace records (v2) David Vrabel 2012-10-04 12:28 ` [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records David Vrabel 2012-10-10 13:26 ` George Dunlap 2012-10-04 12:28 ` [PATCH 2 of 2] xenalyze: decode PV_HYPERCALL_SUBCALL events David Vrabel
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.