[ltt-dev] [PATCH 2/2] Display the VIRT state in resource view
Julien Desfossez
julien.desfossez at polymtl.ca
Thu Sep 9 10:03:41 EDT 2010
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 <julien.desfossez at polymtl.ca>
---
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
More information about the lttng-dev
mailing list