xenalyze: decode new hypercall trace records (v2)
PATCH 1/1 xenalyze: decode new hypercall trace records (v2)
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
PATCH 1/1 xenalyze: decode PV_HYPERCALL_V2 records
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.
analyze.h +2 -0
@@ -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
pv.h new file +41 -0
41 lines not on this page · raw message
xenalyze.c +159 -6
203 lines not on this page · raw message
Re: [PATCH 1 of 2] xenalyze: decode PV_HYPERCALL_V2 records
Quoted 5 lines · David Vrabel
Newer version of Xen produce
TRC_PV_HYPERCALL_V2records instead of the olderTRC_PV_HYPERCALLformat. This updated format doesn't included the IP but it does include select hypercall arguments.Signed-off-by David Vrabel <[email protected]>
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.
Quoted 276 lines
analyze.h +2
-0@@ -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 2pv.h new file +41
-0@@ -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 xenalyze.c +159
-6@@ -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
[email protected]
http://lists.xen.org/xen-devel
PATCH 1/1 xenalyze: decode PV_HYPERCALL_SUBCALL events
In reply to David VrabelDecode 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.
xenalyze.c +11 -6
@@ -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 recouint64_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);