From fb20b385f54457f209425e46a0542f0a60737e29 Mon Sep 17 00:00:00 2001 From: George Dunlap Date: Tue, 23 Sep 2008 16:29:00 +0100 Subject: [PATCH] [global] Rework interval code to unify some output --- analyze.c | 292 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 193 insertions(+), 99 deletions(-) diff --git a/analyze.c b/analyze.c index b6bee97..b9d1f82 100644 --- a/analyze.c +++ b/analyze.c @@ -22,6 +22,11 @@ typedef unsigned long long tsc_t; #define DEFAULT_SAMPLE_SIZE 10240 #define DEFAULT_INTERVAL_LENGTH 1000 +struct array_struct { + unsigned long long *values; + int count; +}; + /* -- Global variables -- */ struct { int fd; @@ -91,16 +96,21 @@ struct { INTERVAL_DOMAIN_GUEST_INTERRUPT, INTERVAL_DOMAIN_GRANT_MAPS } output; + enum { + INTERVAL_MODE_CUSTOM, + INTERVAL_MODE_ARRAY, + INTERVAL_MODE_LIST + } mode; + enum { + INTERVAL_CHECK_NONE, + INTERVAL_CHECK_CR3, + INTERVAL_CHECK_DOMAIN + } check; /* Options for specific interval output types */ union { - struct { - unsigned long long *values; - int count; - } cr3; - struct { - int did; - } domain; + struct array_struct array; }; + int count; } interval; } opt = { .scatterplot_interrupt_eip=0, @@ -1640,8 +1650,13 @@ struct { /* Information about specific interval output types */ union { struct { - struct cr3_value_struct ** array; - } cr3; + struct interval_element ** values; + int count; + } array; + struct { + struct interval_list *head, **tail; + } list; + struct cr3_value_struct *cr3; struct { struct domain_data *d; int guest_vector[INTERVAL_DOMAIN_GUEST_INTERRUPT_MAX]; @@ -2220,9 +2235,11 @@ static inline void print_cycle_summary(struct cycle_summary *s, char *p) { } \ } while(0) +#define INTERVAL_DESC_MAX 31 struct interval_list { struct interval_element *elem; struct interval_list *next; + char desc[INTERVAL_DESC_MAX+1]; /* +1 for the null terminator */ }; void __interval_cycle_percent_output(struct interval_element *e, tsc_t cycles) { @@ -2242,79 +2259,114 @@ void interval_time_output(void) { printf("%lu.%09lu", t.s, t.ns); } -void interval_cr3_schedule_time_header(void) { - if( opt.interval.cr3.count ) { - int i; +void interval_table_output(void) { + int i; - printf("time"); - for(i=0; inext) + interval_cycle_percent_output(p->elem); } - /* Can't see into the future, so no header if cr3 values are - not specified. */ + printf("\n"); } -void interval_cr3_schedule_time_tail(void) { - if( !opt.interval.cr3.count ) { - struct cr3_value_struct *cr3; +void interval_table_tail(void) { + struct interval_list *p; + + printf("time"); + + for(p=P.interval.list.head; p; p = p->next) + printf(" %s", p->desc); + + printf("\n"); +} + +void interval_table_alloc(int count) { + P.interval.array.count = count; + P.interval.array.values = malloc(count * sizeof(struct interval_list *)); + + if(!P.interval.array.values) { + fprintf(stderr, "Malloc failed!\n"); + exit(1); + } + + bzero(P.interval.array.values, count*sizeof(struct interval_list *)); +} + +void interval_list_add(struct interval_element *e, char *desc) { + struct interval_list *p; + + fprintf(warn, "%s: Adding element '%s'\n", __func__, desc); + + if((p=malloc(sizeof(*p)))==NULL) { + fprintf(stderr, "malloc() failed.\n"); + exit(1); + } + + bzero(p, sizeof(*p)); + + p->elem = e; + strncpy(p->desc, desc, INTERVAL_DESC_MAX); + + p->next=NULL; + + if(P.interval.list.head) + *P.interval.list.tail = p; + else + P.interval.list.head = p; + P.interval.list.tail = &p->next; +} + +void interval_cr3_schedule_time_header(void) { + if( opt.interval.mode == INTERVAL_MODE_ARRAY ) { + int i; printf("time"); - for(cr3=P.cr3.head; cr3; cr3 = cr3->gnext) { - printf(" %llx", cr3->gmfn); + for(i=0; igmfn == opt.interval.cr3.values[i]) { - if(P.interval.cr3.array[i]) { + for(i=0; igmfn == opt.interval.array.values[i]) { + if(P.interval.array.values[i]) { fprintf(stderr, "Fatal: duplicate cr3 value %llx!\n", cr3->gmfn); exit(1); } fprintf(stderr, "%s: found gmfn %llx\n", __func__, cr3->gmfn); - P.interval.cr3.array[i] = cr3; - } - } - } -} - -void interval_cr3_schedule_time_output(void) { - struct cr3_value_struct *cr3; - int i; - interval_time_output(); - - if(opt.interval.cr3.count) { - for(i=0; itotal_time.interval.cycles, - opt.interval.cycles)); - clear_interval_cycles(&cr3->total_time.interval); - } else { - printf(" 0.0"); - } + P.interval.array.values[i] = &cr3->total_time.interval; + } } + } else if(opt.interval.mode == INTERVAL_MODE_LIST) { + char desc[32]; + snprintf(desc, 32, "%llx", cr3->gmfn); + interval_list_add(&cr3->total_time.interval, desc); } else { - struct cr3_value_struct *cr3; - for(cr3 = P.cr3.head; cr3; cr3 = cr3->gnext) { - printf(" %.02lf", - __cycles_percent(cr3->total_time.interval.cycles, - opt.interval.cycles)); - clear_interval_cycles(&cr3->total_time.interval); - } + /* Custom */ + P.interval.cr3 = cr3; } - printf("\n"); } void interval_cr3_schedule_ordered_output(void) { @@ -2386,8 +2438,8 @@ void interval_cr3_short_summary_output(void) { struct cycle_summary *hss_array; int i; - if(P.interval.cr3.array[0]) { - struct cr3_value_struct *p = P.interval.cr3.array[0]; + if(P.interval.cr3) { + struct cr3_value_struct *p = P.interval.cr3; interval_time_output(); @@ -2407,6 +2459,30 @@ void interval_cr3_short_summary_output(void) { } } +void interval_domain_value_check(struct domain_data *d) { + if( opt.interval.mode == INTERVAL_MODE_ARRAY ) { + int i; + + for(i=0; idid == opt.interval.array.values[i]) { + if(P.interval.array.values[i]) { + fprintf(stderr, "Fatal: duplicate domain value %d!\n", + d->did); + exit(1); + } + + P.interval.array.values[i] = &d->total_time.interval; + } + } + } else if(opt.interval.mode == INTERVAL_MODE_LIST) { + char desc[32]; + snprintf(desc, 32, "%d", d->did); + interval_list_add(&d->total_time.interval, desc); + } else { + P.interval.domain.d = d; + } +} + void interval_domain_short_summary_header(void) { int i; @@ -2520,10 +2596,17 @@ void interval_domain_grant_maps_output(void) { /* General interval gateways */ void interval_callback(void) { - switch(opt.interval.output) { - case INTERVAL_CR3_SCHEDULE_TIME: - interval_cr3_schedule_time_output(); + /* First, see if we're in generic mode. */ + switch(opt.interval.mode) { + case INTERVAL_MODE_LIST: + case INTERVAL_MODE_ARRAY: + interval_table_output(); + return; + default: break; + } + + switch(opt.interval.output) { case INTERVAL_CR3_SCHEDULE_ORDERED: interval_cr3_schedule_ordered_output(); break; @@ -2539,14 +2622,13 @@ void interval_callback(void) { case INTERVAL_DOMAIN_GRANT_MAPS: interval_domain_grant_maps_output(); break; + default: + break; } } void interval_header(void) { switch(opt.interval.output) { - case INTERVAL_CR3_SCHEDULE_TIME: - interval_cr3_schedule_time_header(); - break; case INTERVAL_CR3_SHORT_SUMMARY: interval_cr3_short_summary_header(); break; @@ -2559,10 +2641,12 @@ void interval_header(void) { } void interval_tail(void) { + if(opt.interval.mode == INTERVAL_MODE_LIST) { + interval_table_tail(); + return; + } + switch(opt.interval.output) { - case INTERVAL_CR3_SCHEDULE_TIME: - interval_cr3_schedule_time_tail(); - break; case INTERVAL_DOMAIN_GUEST_INTERRUPT: interval_domain_guest_interrupt_tail(); break; @@ -3486,7 +3570,8 @@ void cr3_switch(unsigned long long val, struct hvm_data *h) { P.cr3.id++; /* Add to the interval list if appropriate */ - if(v->d->did != DEFAULT_DOMAIN) + if(opt.interval.check == INTERVAL_CHECK_CR3 + && v->d->did != DEFAULT_DOMAIN) interval_cr3_value_check(p); } @@ -4597,6 +4682,7 @@ void hvm_process(struct pcpu_info *p) if(v->d->did == IDLE_DOMAIN) { fprintf(warn, "%s: Strange, hvm record for idle domain!\n", __func__); + dump_generic(warn, ri); return; } @@ -5674,12 +5760,8 @@ void domain_init(struct domain_data *d, int did) d->did = did; d->next = NULL; - if((opt.interval.output == INTERVAL_DOMAIN_SHORT_SUMMARY - || opt.interval.output == INTERVAL_DOMAIN_GUEST_INTERRUPT - || opt.interval.output == INTERVAL_DOMAIN_GRANT_MAPS) - && opt.interval.domain.did == did) { - P.interval.domain.d = d; - } + if(opt.interval.check == INTERVAL_CHECK_DOMAIN) + interval_domain_value_check(d); } struct domain_data * domain_create(int did) @@ -7393,7 +7475,7 @@ char * stringify_cpu_hz(long long cpu_hz) { return cpu_string; } -int parse_cr3_array(char *arg) { +int parse_array(char *arg, struct array_struct *a) { char *p, *q; int n=1, i; @@ -7402,25 +7484,28 @@ int parse_cr3_array(char *arg) { if(*p == ',') n++; - opt.interval.cr3.count = n; - opt.interval.cr3.values = malloc(n * sizeof(unsigned long long)); - P.interval.cr3.array = malloc(n * sizeof(struct cr3_value_struct *)); + fprintf(warn, "%s: Found %d elements\n", __func__, n); + fflush(warn); + a->count = n; + a->values = malloc(n * sizeof(unsigned long long)); - if(!opt.interval.cr3.values || !P.interval.cr3.array) { + if(!a->values) { fprintf(stderr, "Malloc failed!\n"); exit(1); } - bzero(P.interval.cr3.array, n*sizeof(struct cr3_value_struct *)); - /* Now parse the elements */ p = q = arg; for(i=0; ivalues[i] = strtoull(p, &q, 0); if(p == q) { fprintf(stderr, "Bad format: %s\n", q); return -1; } + fprintf(warn, "%s: Found element 0x%llx (%lld)\n", + __func__, a->values[i], + a->values[i]); + fflush(warn); if(*q == ',') q++; else if(*q != '\0') { @@ -7556,11 +7641,15 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state) case OPT_INTERVAL_CR3_SCHEDULE_TIME: { - if(parse_cr3_array(arg) < 0) + if(parse_array(arg, &opt.interval.array) < 0) goto usage; + interval_table_alloc(opt.interval.array.count); opt.interval.output = INTERVAL_CR3_SCHEDULE_TIME; + opt.interval.check = INTERVAL_CHECK_CR3; + opt.interval.mode = INTERVAL_MODE_ARRAY; opt.interval_mode = 1; opt.summary_info = 1; + opt.with_cr3_enumeration = 1; G.output_defined = 1; break; usage: @@ -7571,38 +7660,45 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state) case OPT_INTERVAL_CR3_SCHEDULE_TIME_ALL: opt.interval.output = INTERVAL_CR3_SCHEDULE_TIME; + opt.interval.check = INTERVAL_CHECK_CR3; + opt.interval.mode = INTERVAL_MODE_LIST; opt.interval_mode = 1; opt.summary_info = 1; + opt.with_cr3_enumeration = 1; G.output_defined = 1; break; case OPT_INTERVAL_CR3_SCHEDULE_ORDERED: opt.interval.output = INTERVAL_CR3_SCHEDULE_ORDERED; + opt.interval.check = INTERVAL_CHECK_CR3; opt.interval_mode = 1; opt.summary_info = 1; + opt.with_cr3_enumeration = 1; G.output_defined = 1; break; case OPT_INTERVAL_CR3_SHORT_SUMMARY: { - if(parse_cr3_array(arg) < 0 || opt.interval.cr3.count != 1) + if(parse_array(arg, &opt.interval.array) < 0 + || opt.interval.array.count != 1) goto usage; opt.interval.output = INTERVAL_CR3_SHORT_SUMMARY; + opt.interval.check = INTERVAL_CHECK_CR3; opt.interval_mode = 1; opt.summary_info = 1; + opt.with_cr3_enumeration = 1; G.output_defined = 1; break; } case OPT_INTERVAL_DOMAIN_SHORT_SUMMARY: { - char *inval; - - opt.interval.domain.did = (int)strtol(arg, &inval, 0); - if( inval == arg ) + if((parse_array(arg, &opt.interval.array) < 0) + || opt.interval.array.count != 1) argp_usage(state); opt.interval.output = INTERVAL_DOMAIN_SHORT_SUMMARY; + opt.interval.check = INTERVAL_CHECK_DOMAIN; opt.interval_mode = 1; opt.summary_info = 1; G.output_defined = 1; @@ -7611,13 +7707,12 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state) case OPT_INTERVAL_DOMAIN_GUEST_INTERRUPT: { - char *inval; - - opt.interval.domain.did = (int)strtol(arg, &inval, 0); - if( inval == arg ) + if((parse_array(arg, &opt.interval.array) < 0) + || opt.interval.array.count != 1) argp_usage(state); opt.interval.output = INTERVAL_DOMAIN_GUEST_INTERRUPT; + opt.interval.check = INTERVAL_CHECK_DOMAIN; opt.interval_mode = 1; opt.summary_info = 1; G.output_defined = 1; @@ -7626,13 +7721,12 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state) case OPT_INTERVAL_DOMAIN_GRANT_MAPS: { - char *inval; - - opt.interval.domain.did = (int)strtol(arg, &inval, 0); - if( inval == arg ) + if((parse_array(arg, &opt.interval.array) < 0) + || opt.interval.array.count != 1) argp_usage(state); opt.interval.output = INTERVAL_DOMAIN_GRANT_MAPS; + opt.interval.check = INTERVAL_CHECK_DOMAIN; opt.interval_mode = 1; opt.summary_info = 1; G.output_defined = 1; @@ -7900,6 +7994,8 @@ const char *argp_program_bug_address = "George Dunlap