]> xenbits.xensource.com Git - xenalyze.git/commitdiff
[global] Rework interval code to unify some output
authorGeorge Dunlap <gdunlap@gdunlap-desktop.(none)>
Tue, 23 Sep 2008 15:29:00 +0000 (16:29 +0100)
committerGeorge Dunlap <gdunlap@gdunlap-desktop.(none)>
Tue, 23 Sep 2008 15:29:00 +0000 (16:29 +0100)
analyze.c

index b6bee9769acefdb4b47e905c3e8c3efce85a79ee..b9d1f82f047aea421e9e40d4538ee8ed5713f9ca 100644 (file)
--- 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; i<opt.interval.cr3.count; i++) {
-            printf(" %llx", opt.interval.cr3.values[i]);
+    interval_time_output();
+
+    if(opt.interval.mode == INTERVAL_MODE_ARRAY) {
+        for(i=0; i<P.interval.array.count; i++) {
+            struct interval_element *e = P.interval.array.values[i];
+            if(e) {
+                interval_cycle_percent_output(e);
+            } else {
+                printf(" 0.0");
+            }
         }
-        printf("\n");
+    } else if(opt.interval.mode == INTERVAL_MODE_LIST) {
+        struct interval_list *p;
+        for(p = P.interval.list.head; p; p = p->next)
+            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; i<opt.interval.array.count; i++) {
+            printf(" %llx", opt.interval.array.values[i]);
         }
         printf("\n");
     }
+    /* Can't see into the future, so no header if cr3 values are
+       not specified. */
 }
 
 void interval_cr3_value_check(struct cr3_value_struct *cr3) {
-    if( opt.interval.cr3.count ) {
+    if( opt.interval.mode == INTERVAL_MODE_ARRAY ) {
         int i;
 
-        for(i=0; i<opt.interval.cr3.count; i++) {
-            if(cr3->gmfn == opt.interval.cr3.values[i]) {
-                if(P.interval.cr3.array[i]) {
+        for(i=0; i<opt.interval.array.count; i++) {
+            if(cr3->gmfn == 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; i<opt.interval.cr3.count; i++) {
-            cr3 = P.interval.cr3.array[i];
-            if(cr3) {
-                printf(" %.02lf",
-                       __cycles_percent(cr3->total_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; i<opt.interval.array.count; i++) {
+            if(d->did == 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; i<n; i++) {
-        opt.interval.cr3.values[i] = strtoull(p, &q, 0);
+        a->values[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 <george.dunlap@eu.citrix.c
 
 
 int main(int argc, char *argv[]) {
+    /* Start with warn at stderr. */
+    warn = stderr;
 
     argp_parse(&parser_def, argc, argv, 0, NULL, NULL);
 
@@ -7919,8 +8015,6 @@ int main(int argc, char *argv[]) {
 
     if(opt.dump_cooked || opt.dump_all)
         warn = stdout;
-    else
-        warn = stderr;
         
     init_pcpus();