#define DEFAULT_SAMPLE_SIZE 10240
#define DEFAULT_INTERVAL_LENGTH 1000
+struct array_struct {
+ unsigned long long *values;
+ int count;
+};
+
/* -- Global variables -- */
struct {
int fd;
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,
/* 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];
} \
} 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) {
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) {
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();
}
}
+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;
/* 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;
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;
}
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;
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);
}
if(v->d->did == IDLE_DOMAIN) {
fprintf(warn, "%s: Strange, hvm record for idle domain!\n",
__func__);
+ dump_generic(warn, ri);
return;
}
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)
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;
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') {
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:
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;
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;
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;
int main(int argc, char *argv[]) {
+ /* Start with warn at stderr. */
+ warn = stderr;
argp_parse(&parser_def, argc, argv, 0, NULL, NULL);
if(opt.dump_cooked || opt.dump_all)
warn = stdout;
- else
- warn = stderr;
init_pcpus();