Now when a physical CPU enters in a virtual machine (vmentry) its line is colored in red until a vmexit occurs. That way, we can see which physical CPU are used to run a VM.
Signed-off-by: Julien Desfossez <[email protected]> --- lttv/lttv/state.c | 102 +++++++++++++++++++++++++-- lttv/lttv/state.h | 9 ++- lttv/modules/gui/resourceview/drawing.c | 11 +++ lttv/modules/gui/resourceview/drawing.h | 9 +++ lttv/modules/gui/resourceview/eventhooks.c | 21 +++++- lttv/modules/gui/resourceview/eventhooks.h | 3 + lttv/modules/gui/resourceview/processlist.c | 17 +++++ lttv/modules/gui/resourceview/processlist.h | 4 +- 8 files changed, 167 insertions(+), 9 deletions(-) diff --git a/lttv/lttv/state.c b/lttv/lttv/state.c index 6987fa9..353acca 100644 --- a/lttv/lttv/state.c +++ b/lttv/lttv/state.c @@ -180,7 +180,8 @@ LttvCPUMode LTTV_CPU_BUSY, LTTV_CPU_IRQ, LTTV_CPU_SOFT_IRQ, - LTTV_CPU_TRAP; + LTTV_CPU_TRAP, + LTTV_CPU_VIRT; LttvIRQMode LTTV_IRQ_UNKNOWN, @@ -210,7 +211,8 @@ static GQuark LTTV_STATE_RESOURCE_IRQS, LTTV_STATE_RESOURCE_SOFT_IRQS, LTTV_STATE_RESOURCE_TRAPS, - LTTV_STATE_RESOURCE_BLKDEVS; + LTTV_STATE_RESOURCE_BLKDEVS, + LTTV_STATE_RESOURCE_VIRT; static void create_max_time(LttvTraceState *tcs); @@ -362,13 +364,23 @@ static void expand_syscall_table(LttvTraceState *ts, int id) static void expand_virt_table(LttvTraceState *ts, int id) { LttvNameTables *nt = ts->name_tables; - guint new_nb; + LttvTrapState *old_table; + guint new_nb, i; new_nb = check_expand(nt->nb_virt, id); if(likely(new_nb == nt->nb_virt)) return; + expand_name_table(ts, &nt->virt_names, nt->nb_virt, new_nb); fill_name_table(ts, nt->virt_names, nt->nb_virt, new_nb, "virt"); + + old_table = ts->virt_states; + ts->virt_states = g_new(LttvVirtState, new_nb); + memcpy(ts->virt_states, old_table, nt->nb_virt * sizeof(LttvVirtState)); + g_free(old_table); + for(i = nt->nb_virt; i < new_nb; i++) + ts->virt_states[i].running = 0; + /* Update the table size */ nt->nb_virt = new_nb; } @@ -523,6 +535,9 @@ static void restore_init_state(LttvTraceState *self) if(self->cpu_states[i].trap_stack->len) g_array_remove_range(self->cpu_states[i].trap_stack, 0, self->cpu_states[i].trap_stack->len); + if(self->cpu_states[i].virt_stack->len) + g_array_remove_range(self->cpu_states[i].virt_stack, 0, + self->cpu_states[i].virt_stack->len); } } @@ -549,6 +564,12 @@ static void restore_init_state(LttvTraceState *self) //g_hash_table_steal_all(self->bdev_states); g_hash_table_foreach_steal(self->bdev_states, rettrue, NULL); + /* reset virt states */ + for(i=0; i<nb_virt; i++) { + self->virt_states[i].running = 0; + } + + #if 0 nb_tracefile = self->parent.tracefiles->len; @@ -704,6 +725,7 @@ static void init(LttvTracesetState *self, LttvTraceset *ts) tcs->cpu_states[j].irq_stack = g_array_new(FALSE, FALSE, sizeof(gint)); tcs->cpu_states[j].softirq_stack = g_array_new(FALSE, FALSE, sizeof(gint)); tcs->cpu_states[j].trap_stack = g_array_new(FALSE, FALSE, sizeof(gint)); + tcs->cpu_states[j].virt_stack = g_array_new(FALSE, FALSE, sizeof(gint)); g_assert(tcs->cpu_states[j].mode_stack != NULL); } @@ -724,6 +746,9 @@ static void init(LttvTracesetState *self, LttvTraceset *ts) /* init bdev resource stuff */ tcs->bdev_states = g_hash_table_new(g_int_hash, g_int_equal); + /* init virt stuff */ + tcs->virt_states = g_new(LttvVirtState, tcs->name_tables->nb_virt); + restore_init_state(tcs); for(j = 0 ; j < nb_tracefile ; j++) { tfcs = @@ -1419,6 +1444,13 @@ static LttvCPUState *lttv_state_copy_cpu_states(LttvCPUState *states, guint n) g_array_index(retval[i].mode_stack, GQuark, j) = g_array_index(states[i].mode_stack, GQuark, j); } + + retval[i].virt_stack = g_array_new(FALSE, FALSE, sizeof(gint)); + g_array_set_size(retval[i].virt_stack, states[i].virt_stack->len); + for(j=0; j<states[i].virt_stack->len; j++) { + g_array_index(retval[i].virt_stack, gint, j) = + g_array_index(states[i].virt_stack, gint, j); + } } return retval; @@ -1433,6 +1465,7 @@ static void lttv_state_free_cpu_states(LttvCPUState *states, guint n) g_array_free(states[i].irq_stack, TRUE); g_array_free(states[i].softirq_stack, TRUE); g_array_free(states[i].trap_stack, TRUE); + g_array_free(states[i].virt_stack, TRUE); } g_free(states); @@ -1509,6 +1542,26 @@ static void lttv_state_free_trap_states(LttvTrapState *states, guint n) g_free(states); } +static LttvVirtState * +lttv_state_copy_virt_states(LttvVirtState *states, guint n) +{ + guint i; + LttvVirtState *retval; + + retval = g_new(LttvVirtState, n); + + for(i=0; i<n; i++) { + retval[i].running = states[i].running; + } + + return retval; +} + +static void lttv_state_free_virt_states(LttvVirtState *states, guint n) +{ + g_free(states); +} + /* bdevstate stuff */ static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint16 devcode) @@ -1601,7 +1654,7 @@ static void lttv_state_free_blkdev_hashtable(GHashTable *ht) static void state_save(LttvTraceState *self, LttvAttribute *container) { - guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps; + guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps, nb_virt; LttvTracefileState *tfcs; @@ -1709,12 +1762,21 @@ static void state_save(LttvTraceState *self, LttvAttribute *container) value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_BLKDEVS, LTTV_POINTER); *(value.v_pointer) = lttv_state_copy_blkdev_hashtable(self->bdev_states); + + /* save the virt state */ + nb_virt = self->name_tables->nb_virt; + { + value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_VIRT, + LTTV_POINTER); + *(value.v_pointer) = lttv_state_copy_virt_states(self->virt_states, nb_virt); + } + } static void state_restore(LttvTraceState *self, LttvAttribute *container) { - guint i, nb_tracefile, pid, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps; + guint i, nb_tracefile, pid, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps, nb_virt; LttvTracefileState *tfcs; @@ -1794,6 +1856,13 @@ static void state_restore(LttvTraceState *self, LttvAttribute *container) lttv_state_free_blkdev_hashtable(self->bdev_states); self->bdev_states = lttv_state_copy_blkdev_hashtable(*(value.v_pointer)); + /* restore virt resource states */ + nb_virt = self->name_tables->nb_virt; + type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_VIRT, &value); + g_assert(type == LTTV_POINTER); + lttv_state_free_virt_states(self->virt_states, nb_virt); + self->virt_states = lttv_state_copy_virt_states(*(value.v_pointer), nb_virt); + for(i = 0 ; i < nb_tracefile ; i++) { tfcs = LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles, @@ -2604,6 +2673,14 @@ static gboolean kvm_entry(void *hook_data, void *call_data) submode = nt->virt_names[vcpu]; if(process->pid != 0) push_state(s, LTTV_STATE_VIRT , submode); + + /* update cpu status */ + cpu_push_mode(s->cpu_state, LTTV_CPU_VIRT); + + /* update trap status */ + g_array_append_val(s->cpu_state->virt_stack, vcpu); + ts->virt_states[vcpu].running++; + return FALSE; } @@ -2616,6 +2693,19 @@ static gboolean kvm_exit(void *hook_data, void *call_data) if(process->pid != 0) pop_state(s, LTTV_STATE_VIRT); + + /* update cpu status */ + cpu_pop_mode(s->cpu_state); + + /* update virt status */ + if (s->cpu_state->virt_stack->len > 0) { + gint last = g_array_index(s->cpu_state->virt_stack, gint, + s->cpu_state->virt_stack->len-1); + if(ts->virt_states[last].running) + ts->virt_states[last].running--; + g_array_remove_index(s->cpu_state->virt_stack, + s->cpu_state->virt_stack->len-1); + } return FALSE; } @@ -4532,6 +4622,7 @@ static void module_init() LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states"); LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states"); LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states"); + LTTV_STATE_RESOURCE_VIRT = g_quark_from_string("virt resource states"); LTT_CHANNEL_FD_STATE = g_quark_from_string("fd_state"); LTT_CHANNEL_GLOBAL_STATE = g_quark_from_string("global_state"); @@ -4628,6 +4719,7 @@ static void module_init() LTTV_CPU_IRQ = g_quark_from_string("irq"); LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq"); LTTV_CPU_TRAP = g_quark_from_string("trap"); + LTTV_CPU_VIRT = g_quark_from_string("virt"); LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown"); LTTV_IRQ_IDLE = g_quark_from_string("idle"); diff --git a/lttv/lttv/state.h b/lttv/lttv/state.h index b6da6db..2be86a6 100644 --- a/lttv/lttv/state.h +++ b/lttv/lttv/state.h @@ -248,7 +248,8 @@ extern LttvCPUMode LTTV_CPU_BUSY, LTTV_CPU_IRQ, LTTV_CPU_SOFT_IRQ, - LTTV_CPU_TRAP; + LTTV_CPU_TRAP, + LTTV_CPU_VIRT; typedef GQuark LttvIRQMode; extern LttvIRQMode @@ -348,6 +349,7 @@ typedef struct _LttvCPUState { GArray *irq_stack; GArray *softirq_stack; GArray *trap_stack; + GArray *virt_stack; } LttvCPUState; typedef struct _LttvIRQState { @@ -367,6 +369,10 @@ typedef struct _LttvBdevState { GArray *mode_stack; } LttvBdevState; +typedef struct _LttvVirtState { + guint running; /* number of times it is currently running (on different processors) */ +} LttvVirtState; + typedef struct _LttvNameTables { GQuark *syscall_names; guint nb_syscalls; @@ -406,6 +412,7 @@ struct _LttvTraceState { /* FIXME should be a g_array to deal with resize and copy. */ LttvTrapState *trap_states; /* state of each trap */ GHashTable *bdev_states; /* state of the block devices */ + LttvVirtState *virt_states; /* state of each trap */ }; struct _LttvTraceStateClass { diff --git a/lttv/modules/gui/resourceview/drawing.c b/lttv/modules/gui/resourceview/drawing.c index 033475a..8aef0fc 100644 --- a/lttv/modules/gui/resourceview/drawing.c +++ b/lttv/modules/gui/resourceview/drawing.c @@ -91,6 +91,7 @@ GdkColor drawing_colors_cpu[NUM_COLORS_CPU] = { 0, 0xFFFF, 0x5E00, 0x0000 }, /* COL_CPU_IRQ */ { 0, 0xFFFF, 0x9400, 0x9600 }, /* COL_CPU_SOFT_IRQ */ { 0, 0xFF00, 0xFF00, 0x0100 }, /* COL_CPU_TRAP */ + { 0, 0xFFFF, 0x0000, 0x0000 }, /* COL_CPU_VIRT */ }; GdkColor drawing_colors_irq[NUM_COLORS_IRQ] = @@ -123,6 +124,13 @@ GdkColor drawing_colors_bdev[NUM_COLORS_BDEV] = { 0, 0xFFFF, 0x0000, 0x0000 }, /* COL_BDEV_BUSY_WRITING */ }; +GdkColor drawing_colors_virt[NUM_COLORS_VIRT] = +{ /* Pixel, R, G, B */ + { 0, 0x0000, 0x0000, 0x0000 }, /* COL_VIRT_UNKNOWN */ + { 0, 0x0000, 0x0000, 0x0000 }, /* FIXME : COL_VIRT_IDLE */ + { 0, 0xFF00, 0xFF00, 0x0100 }, /* FIXME : COL_VIRT_BUSY */ +}; + /***************************************************************************** * drawing functions * *****************************************************************************/ @@ -1072,6 +1080,8 @@ Drawing_t *drawing_construct(ControlFlowData *control_flow_data) TRUE, success); gdk_colormap_alloc_colors(colormap, drawing_colors_bdev, NUM_COLORS_BDEV, FALSE, TRUE, success); + gdk_colormap_alloc_colors(colormap, drawing_colors_virt, NUM_COLORS_VIRT, FALSE, + TRUE, success); drawing->gc = gdk_gc_new(GDK_DRAWABLE(main_window_get_widget(control_flow_data->tab)->window)); @@ -1133,6 +1143,7 @@ void drawing_destroy(Drawing_t *drawing) gdk_colormap_free_colors(colormap, drawing_colors_soft_irq, NUM_COLORS_IRQ); gdk_colormap_free_colors(colormap, drawing_colors_trap, NUM_COLORS_TRAP); gdk_colormap_free_colors(colormap, drawing_colors_bdev, NUM_COLORS_BDEV); + gdk_colormap_free_colors(colormap, drawing_colors_virt, NUM_COLORS_VIRT); // Do not unref here, Drawing_t destroyed by it's widget. //g_object_unref( G_OBJECT(drawing->drawing_area)); diff --git a/lttv/modules/gui/resourceview/drawing.h b/lttv/modules/gui/resourceview/drawing.h index 8b0070b..fc0e7ec 100644 --- a/lttv/modules/gui/resourceview/drawing.h +++ b/lttv/modules/gui/resourceview/drawing.h @@ -57,6 +57,7 @@ typedef enum _draw_color_cpu { COL_CPU_IRQ, COL_CPU_SOFT_IRQ, COL_CPU_TRAP, + COL_CPU_VIRT, NUM_COLORS_CPU } draw_color_cpu; @@ -90,12 +91,20 @@ typedef enum _draw_color_bdev { NUM_COLORS_BDEV } draw_color_bdev; +typedef enum _draw_color_virt { + COL_VIRT_UNKNOWN, + COL_VIRT_IDLE, + COL_VIRT_BUSY, + NUM_COLORS_VIRT +} draw_color_virt; + extern GdkColor drawing_colors[NUM_COLORS]; extern GdkColor drawing_colors_cpu[NUM_COLORS_CPU]; extern GdkColor drawing_colors_irq[NUM_COLORS_IRQ]; extern GdkColor drawing_colors_soft_irq[NUM_COLORS_SOFT_IRQ]; extern GdkColor drawing_colors_trap[NUM_COLORS_TRAP]; extern GdkColor drawing_colors_bdev[NUM_COLORS_BDEV]; +extern GdkColor drawing_colors_virt[NUM_COLORS_VIRT]; /* This part of the viewer does : * Draw horizontal lines, getting graphic context as arg. diff --git a/lttv/modules/gui/resourceview/eventhooks.c b/lttv/modules/gui/resourceview/eventhooks.c index 271e8d2..18e2c07 100644 --- a/lttv/modules/gui/resourceview/eventhooks.c +++ b/lttv/modules/gui/resourceview/eventhooks.c @@ -286,7 +286,11 @@ static void cpu_set_line_color(PropertiesLine *prop_line, LttvCPUState *s) } else if(present_state == LTTV_CPU_TRAP) { prop_line->color = drawing_colors_cpu[COL_CPU_TRAP]; - } else { + } + else if(present_state == LTTV_CPU_VIRT) { + prop_line->color = drawing_colors_cpu[COL_CPU_VIRT]; + } + else { prop_line->color = drawing_colors_cpu[COL_CPU_UNKNOWN]; } } @@ -352,6 +356,15 @@ static void bdev_set_line_color(PropertiesLine *prop_line, LttvBdevState *s) } } +static void virt_set_line_color(PropertiesLine *prop_line, LttvVirtState *s) +{ + GQuark present_state; + if(s->running == 0) + prop_line->color = drawing_colors_virt[COL_VIRT_IDLE]; + else + prop_line->color = drawing_colors_virt[COL_VIRT_BUSY]; +} + /* before_schedchange_hook * * This function basically draw lines and icons. Two types of lines are drawn : @@ -624,6 +637,7 @@ int after_schedchange_hook(void *hook_data, void *call_data) int before_execmode_hook_irq(void *hook_data, void *call_data); int before_execmode_hook_soft_irq(void *hook_data, void *call_data); int before_execmode_hook_trap(void *hook_data, void *call_data); +int before_execmode_hook_virt(void *hook_data, void *call_data); /* before_execmode_hook * @@ -661,6 +675,7 @@ int before_execmode_hook(void *hook_data, void *call_data) before_execmode_hook_irq(hook_data, call_data); before_execmode_hook_soft_irq(hook_data, call_data); before_execmode_hook_trap(hook_data, call_data); +// before_execmode_hook_virt(hook_data, call_data); /* we are in a execmode, before the state update. We must draw the * items corresponding to the state before it changes : now is the right @@ -2026,7 +2041,9 @@ void draw_closure(gpointer key, gpointer value, gpointer user_data) // the lookup may return null; bdev_set_line_color must act appropriately bdev_set_line_color(&prop_line, bdev); } - + else if(hashed_process_data->type == RV_RESOURCE_VIRT) { + virt_set_line_color(&prop_line, &ts->virt_states[process_info->id]); + } draw_line((void*)&prop_line, (void*)&draw_context); } diff --git a/lttv/modules/gui/resourceview/eventhooks.h b/lttv/modules/gui/resourceview/eventhooks.h index 9ff63b3..e9bf8b6 100644 --- a/lttv/modules/gui/resourceview/eventhooks.h +++ b/lttv/modules/gui/resourceview/eventhooks.h @@ -137,4 +137,7 @@ HashedResourceData *resourcelist_obtain_trap(ControlFlowData *resourceview_data, HashedResourceData *resourcelist_obtain_bdev(ControlFlowData *resourceview_data, guint trace_num, guint id); +HashedResourceData *resourcelist_obtain_virt(ControlFlowData *resourceview_data, + guint trace_num, guint id); + #endif // _EVENT_HOOKS_H diff --git a/lttv/modules/gui/resourceview/processlist.c b/lttv/modules/gui/resourceview/processlist.c index ee24ba6..e317aff 100644 --- a/lttv/modules/gui/resourceview/processlist.c +++ b/lttv/modules/gui/resourceview/processlist.c @@ -446,6 +446,7 @@ ProcessList *processlist_construct(void) process_list->restypes[RV_RESOURCE_SOFT_IRQ].hash_table = g_hash_table_new(ru_numeric_hash_fct, ru_numeric_equ_fct); process_list->restypes[RV_RESOURCE_TRAP].hash_table = g_hash_table_new(ru_numeric_hash_fct, ru_numeric_equ_fct); process_list->restypes[RV_RESOURCE_BDEV].hash_table = g_hash_table_new(ru_numeric_hash_fct, ru_numeric_equ_fct); + process_list->restypes[RV_RESOURCE_VIRT].hash_table = g_hash_table_new(ru_numeric_hash_fct, ru_numeric_equ_fct); return process_list; } @@ -578,6 +579,18 @@ GQuark make_bdev_name(ControlFlowData *resourceview_data, guint trace_num, guint return name; } +GQuark make_virt_name(ControlFlowData *resourceview_data, guint trace_num, guint id) +{ + GQuark name; + gchar *str; + + str = g_strdup_printf("Virt %u", id); + name = g_quark_from_string(str); + g_free(str); + + return name; +} + HashedResourceData *resourcelist_obtain_machine(ControlFlowData *resourceview_data, guint trace_num, guint id) { ResourceUniqueNumeric *ru = g_new(ResourceUniqueNumeric, 1); @@ -819,3 +832,7 @@ HashedResourceData *resourcelist_obtain_bdev(ControlFlowData *resourceview_data, return resourcelist_obtain_generic(resourceview_data, RV_RESOURCE_BDEV, trace_num, id, make_bdev_name); } +HashedResourceData *resourcelist_obtain_virt(ControlFlowData *resourceview_data, guint trace_num, guint id) +{ + return resourcelist_obtain_generic(resourceview_data, RV_RESOURCE_VIRT, trace_num, id, make_virt_name); +} diff --git a/lttv/modules/gui/resourceview/processlist.h b/lttv/modules/gui/resourceview/processlist.h index ce32e16..7126fc6 100644 --- a/lttv/modules/gui/resourceview/processlist.h +++ b/lttv/modules/gui/resourceview/processlist.h @@ -47,7 +47,8 @@ #define RV_RESOURCE_SOFT_IRQ 3 #define RV_RESOURCE_TRAP 4 #define RV_RESOURCE_BDEV 5 -#define RV_RESOURCE_COUNT 6 +#define RV_RESOURCE_VIRT 6 +#define RV_RESOURCE_COUNT 7 /* Enumeration of the columns */ enum @@ -304,5 +305,6 @@ HashedResourceData *resourcelist_obtain_irq(ControlFlowData *resourceview_data, HashedResourceData *resourcelist_obtain_soft_irq(ControlFlowData *resourceview_data, guint trace_num, guint id); HashedResourceData *resourcelist_obtain_trap(ControlFlowData *resourceview_data, guint trace_num, guint id); HashedResourceData *resourcelist_obtain_bdev(ControlFlowData *resourceview_data, guint trace_num, guint id); +HashedResourceData *resourcelist_obtain_virt(ControlFlowData *resourceview_data, guint trace_num, guint id); #endif // _PROCESS_LIST_H -- 1.7.0.4 _______________________________________________ ltt-dev mailing list [email protected] http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
