[ltt-dev] [PATCH 1/2] Add the VIRT state

Julien Desfossez julien.desfossez at polymtl.ca
Thu Sep 9 10:03:40 EDT 2010


The VIRT state is used to represent the CPU state of a machine when
there are virtual machines running. For now it only work with KVM but
could be extended to other virtualization technologies.
In the control flow view, a process entering in a virtual machine CPU
(vmentry) will be represented in red until a vmexit occurs.

Signed-off-by: Julien Desfossez <julien.desfossez at polymtl.ca>
---
 lttv/lttv/state.c                         |   97 +++++++++++++++++++++++++++--
 lttv/lttv/state.h                         |   13 +++-
 lttv/modules/gui/controlflow/drawing.c    |   17 +++++
 lttv/modules/gui/controlflow/drawing.h    |    1 +
 lttv/modules/gui/controlflow/eventhooks.c |    2 +
 5 files changed, 122 insertions(+), 8 deletions(-)

diff --git a/lttv/lttv/state.c b/lttv/lttv/state.c
index 871df9b..6987fa9 100644
--- a/lttv/lttv/state.c
+++ b/lttv/lttv/state.c
@@ -64,7 +64,8 @@ GQuark
 	LTT_CHANNEL_KERNEL,
 	LTT_CHANNEL_MM,
 	LTT_CHANNEL_USERSPACE,
-	LTT_CHANNEL_BLOCK;
+	LTT_CHANNEL_BLOCK,
+	LTT_CHANNEL_KVM;
 
 /* Events Quarks */
 
@@ -103,7 +104,9 @@ GQuark
 	LTT_EVENT_KPROBE,
 	LTT_EVENT_OPEN,
 	LTT_EVENT_READ,
-	LTT_EVENT_POLL_EVENT;
+	LTT_EVENT_POLL_EVENT,
+	LTT_EVENT_VIRT_ENTRY,
+	LTT_EVENT_VIRT_EXIT;
 
 /* Fields Quarks */
 
@@ -138,7 +141,8 @@ GQuark
 	LTT_FIELD_IP,
 	LTT_FIELD_FD,
 	LTT_FIELD_STATE,
-	LTT_FIELD_CPU_ID;
+	LTT_FIELD_CPU_ID,
+	LTT_FIELD_VCPU_ID;
 
 LttvExecutionMode
 	LTTV_STATE_MODE_UNKNOWN,
@@ -146,7 +150,8 @@ LttvExecutionMode
 	LTTV_STATE_SYSCALL,
 	LTTV_STATE_TRAP,
 	LTTV_STATE_IRQ,
-	LTTV_STATE_SOFT_IRQ;
+	LTTV_STATE_SOFT_IRQ,
+	LTTV_STATE_VIRT;
 
 LttvExecutionSubmode
 	LTTV_STATE_SUBMODE_UNKNOWN,
@@ -354,6 +359,20 @@ static void expand_syscall_table(LttvTraceState *ts, int id)
 	nt->nb_syscalls = new_nb;
 }
 
+static void expand_virt_table(LttvTraceState *ts, int id)
+{
+	LttvNameTables *nt = ts->name_tables;
+	guint new_nb;
+
+	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");
+	/* Update the table size */
+	nt->nb_virt = new_nb;
+}
+
 static void expand_kprobe_table(LttvTraceState *ts, guint64 ip, char *symbol)
 {
 	LttvNameTables *nt = ts->name_tables;
@@ -443,7 +462,7 @@ static void expand_soft_irq_table(LttvTraceState *ts, int id)
 
 static void restore_init_state(LttvTraceState *self)
 {
-	guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
+	guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps, nb_virt;
 
 	//LttvTracefileState *tfcs;
 
@@ -471,6 +490,7 @@ static void restore_init_state(LttvTraceState *self)
 	nb_irqs = self->name_tables->nb_irqs;
 	nb_soft_irqs = self->name_tables->nb_soft_irqs;
 	nb_traps = self->name_tables->nb_traps;
+	nb_virt = self->name_tables->nb_virt;
 
 	/* Put the per cpu running_process to beginning state : process 0. */
 	for(i=0; i< nb_cpus; i++) {
@@ -2014,6 +2034,24 @@ static void create_name_tables(LttvTraceState *tcs)
 	lttv_trace_hook_remove_all(&hooks);
 
 	if(!lttv_trace_find_hook(tcs->parent.t,
+			LTT_CHANNEL_KVM,
+			LTT_EVENT_VIRT_ENTRY,
+			FIELD_ARRAY(LTT_FIELD_VCPU_ID),
+			NULL, NULL, &hooks)) {
+
+		name_tables->nb_virt = 256;
+		name_tables->virt_names = g_new(GQuark, 256);
+		for(i = 0 ; i < 256 ; i++) {
+			g_string_printf(fe_name, "vcpu %d", i);
+			name_tables->virt_names[i] = g_quark_from_string(fe_name->str);
+		}
+	} else {
+		name_tables->virt_names = NULL;
+		name_tables->nb_virt = 0;
+	}
+	lttv_trace_hook_remove_all(&hooks);
+
+	if(!lttv_trace_find_hook(tcs->parent.t,
 				LTT_CHANNEL_KERNEL,
 				LTT_EVENT_TRAP_ENTRY,
 				FIELD_ARRAY(LTT_FIELD_TRAP_ID),
@@ -2124,6 +2162,7 @@ static void free_name_tables(LttvTraceState *tcs)
 
  // g_free(name_tables->eventtype_names);
 	if(name_tables->syscall_names) g_free(name_tables->syscall_names);
+	if(name_tables->virt_names) g_free(name_tables->virt_names);
 	if(name_tables->trap_names) g_free(name_tables->trap_names);
 	if(name_tables->irq_names) g_free(name_tables->irq_names);
 	if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
@@ -2548,6 +2587,37 @@ static gboolean syscall_exit(void *hook_data, void *call_data)
 	return FALSE;
 }
 
+static gboolean kvm_entry(void *hook_data, void *call_data)
+{
+	LttvTracefileState *s = (LttvTracefileState *)call_data;
+	guint cpu = s->cpu;
+	LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+	LttvProcessState *process = ts->running_process[cpu];
+	LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
+	LttvTraceHook *th = (LttvTraceHook *)hook_data;
+	struct marker_field *f = lttv_trace_get_hook_field(th, 0);
+	LttvExecutionSubmode submode;
+	LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
+
+	guint vcpu = ltt_event_get_unsigned(e, f);
+	expand_virt_table(ts, vcpu);
+	submode = nt->virt_names[vcpu];
+	if(process->pid != 0)
+		push_state(s, LTTV_STATE_VIRT , submode);
+	return FALSE;
+}
+
+static gboolean kvm_exit(void *hook_data, void *call_data)
+{
+	LttvTracefileState *s = (LttvTracefileState *)call_data;
+	guint cpu = s->cpu;
+	LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
+	LttvProcessState *process = ts->running_process[cpu];
+
+	if(process->pid != 0)
+		pop_state(s, LTTV_STATE_VIRT);
+	return FALSE;
+}
 
 static gboolean trap_entry(void *hook_data, void *call_data)
 {
@@ -3619,6 +3689,18 @@ void lttv_state_add_event_hooks(LttvTracesetState *self)
 				syscall_exit, NULL, &hooks);
 
 		lttv_trace_find_hook(ts->parent.t,
+				LTT_CHANNEL_KVM,
+				LTT_EVENT_VIRT_ENTRY,
+				FIELD_ARRAY(LTT_FIELD_VCPU_ID),
+				kvm_entry, NULL, &hooks);
+
+		lttv_trace_find_hook(ts->parent.t,
+				LTT_CHANNEL_KVM,
+				LTT_EVENT_VIRT_EXIT,
+				NULL,
+				kvm_exit, NULL, &hooks);
+
+		lttv_trace_find_hook(ts->parent.t,
 				LTT_CHANNEL_KERNEL,
 				LTT_EVENT_TRAP_ENTRY,
 				FIELD_ARRAY(LTT_FIELD_TRAP_ID),
@@ -4417,6 +4499,7 @@ static void module_init()
 	LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
 	LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
 	LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
+	LTTV_STATE_VIRT = g_quark_from_string("VIRT");
 	LTTV_STATE_TRAP = g_quark_from_string("TRAP");
 	LTTV_STATE_IRQ = g_quark_from_string("IRQ");
 	LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
@@ -4461,6 +4544,7 @@ static void module_init()
 	LTT_CHANNEL_TASK_STATE       = g_quark_from_string("task_state");
 	LTT_CHANNEL_VM_STATE         = g_quark_from_string("vm_state");
 	LTT_CHANNEL_KPROBE_STATE     = g_quark_from_string("kprobe_state");
+	LTT_CHANNEL_KVM       = g_quark_from_string("kvm");
 	LTT_CHANNEL_FS        = g_quark_from_string("fs");
 	LTT_CHANNEL_KERNEL    = g_quark_from_string("kernel");
 	LTT_CHANNEL_MM        = g_quark_from_string("mm");
@@ -4469,6 +4553,8 @@ static void module_init()
 
 	LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
 	LTT_EVENT_SYSCALL_EXIT  = g_quark_from_string("syscall_exit");
+	LTT_EVENT_VIRT_ENTRY = g_quark_from_string("kvm_entry");
+	LTT_EVENT_VIRT_EXIT  = g_quark_from_string("kvm_exit");
 	LTT_EVENT_TRAP_ENTRY    = g_quark_from_string("trap_entry");
 	LTT_EVENT_TRAP_EXIT     = g_quark_from_string("trap_exit");
 	LTT_EVENT_PAGE_FAULT_ENTRY    = g_quark_from_string("page_fault_entry");
@@ -4534,6 +4620,7 @@ static void module_init()
 	LTT_FIELD_FD            = g_quark_from_string("fd");
 	LTT_FIELD_STATE         = g_quark_from_string("state");
 	LTT_FIELD_CPU_ID        = g_quark_from_string("cpu_id");
+	LTT_FIELD_VCPU_ID        = g_quark_from_string("vcpu");
 
 	LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
 	LTTV_CPU_IDLE = g_quark_from_string("idle");
diff --git a/lttv/lttv/state.h b/lttv/lttv/state.h
index 1e6efb5..b6da6db 100644
--- a/lttv/lttv/state.h
+++ b/lttv/lttv/state.h
@@ -71,7 +71,8 @@ extern GQuark
 	LTT_CHANNEL_KERNEL,
 	LTT_CHANNEL_MM,
 	LTT_CHANNEL_USERSPACE,
-	LTT_CHANNEL_BLOCK;
+	LTT_CHANNEL_BLOCK,
+	LTT_CHANNEL_KVM;
 
 /* Events Quarks */
 
@@ -110,7 +111,9 @@ extern GQuark
 	LTT_EVENT_KPROBE,
 	LTT_EVENT_OPEN,
 	LTT_EVENT_READ,
-	LTT_EVENT_POLL_EVENT;
+	LTT_EVENT_POLL_EVENT,
+	LTT_EVENT_VIRT_ENTRY,
+	LTT_EVENT_VIRT_EXIT;
 
 /* Fields Quarks */
 
@@ -144,7 +147,8 @@ extern GQuark
 	LTT_FIELD_IP,
 	LTT_FIELD_FD,
 	LTT_FIELD_STATE,
-	LTT_FIELD_CPU_ID;
+	LTT_FIELD_CPU_ID,
+	LTT_FIELD_VCPU_ID;
 
 typedef struct _LttvTracesetState LttvTracesetState;
 typedef struct _LttvTracesetStateClass LttvTracesetStateClass;
@@ -196,6 +200,7 @@ extern LttvExecutionMode
 	LTTV_STATE_TRAP,
 	LTTV_STATE_IRQ,
 	LTTV_STATE_SOFT_IRQ,
+	LTTV_STATE_VIRT,
 	LTTV_STATE_MODE_UNKNOWN;
 
 
@@ -372,6 +377,8 @@ typedef struct _LttvNameTables {
 	GQuark *soft_irq_names;
 	guint nb_soft_irqs;
 	GHashTable *kprobe_hash;
+	GQuark *virt_names;
+	guint nb_virt;
 } LttvNameTables;
 
 struct _LttvTraceState {
diff --git a/lttv/modules/gui/controlflow/drawing.c b/lttv/modules/gui/controlflow/drawing.c
index 10df57d..ecf2493 100644
--- a/lttv/modules/gui/controlflow/drawing.c
+++ b/lttv/modules/gui/controlflow/drawing.c
@@ -70,6 +70,7 @@ GdkColor drawing_colors[NUM_COLORS] =
   { 0, 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_WHITE */
   { 0, 0x0000, 0xFF00, 0x0000 }, /* COL_RUN_USER_MODE : green */
   { 0, 0x0100, 0x9E00, 0xFFFF }, /* COL_RUN_SYSCALL : pale blue */
+  { 0, 0xFFFF, 0x0000, 0x0000 }, /* COL_RUN_VIRT : red */
   { 0, 0xFF00, 0xFF00, 0x0100 }, /* COL_RUN_TRAP : yellow */
   { 0, 0xFFFF, 0x5E00, 0x0000 }, /* COL_RUN_IRQ : orange */
   { 0, 0xFFFF, 0x9400, 0x9600 }, /* COL_RUN_SOFT_IRQ : pink */
@@ -246,6 +247,22 @@ void drawing_data_request(Drawing_t *drawing,
           &hooks);
 
       lttv_trace_find_hook(ts->parent.t,
+          LTT_CHANNEL_KVM,
+          LTT_EVENT_VIRT_ENTRY,
+          FIELD_ARRAY(LTT_FIELD_VCPU_ID),
+          before_execmode_hook,
+          events_request,
+          &hooks);
+
+	  lttv_trace_find_hook(ts->parent.t,
+          LTT_CHANNEL_KVM,
+          LTT_EVENT_VIRT_EXIT,
+          NULL,
+          before_execmode_hook,
+          events_request,
+          &hooks);
+
+      lttv_trace_find_hook(ts->parent.t,
           LTT_CHANNEL_KERNEL,
           LTT_EVENT_TRAP_ENTRY,
           FIELD_ARRAY(LTT_FIELD_TRAP_ID),
diff --git a/lttv/modules/gui/controlflow/drawing.h b/lttv/modules/gui/controlflow/drawing.h
index 3e4b3dc..f85e7c8 100644
--- a/lttv/modules/gui/controlflow/drawing.h
+++ b/lttv/modules/gui/controlflow/drawing.h
@@ -38,6 +38,7 @@ typedef enum _draw_color {
                 COL_WHITE,
                 COL_RUN_USER_MODE,/* green */
                 COL_RUN_SYSCALL,  /* pale blue */
+				COL_RUN_VIRT,     /* red */
                 COL_RUN_TRAP,     /* yellow */
                 COL_RUN_IRQ,      /* orange */
                 COL_RUN_SOFT_IRQ, /* red */
diff --git a/lttv/modules/gui/controlflow/eventhooks.c b/lttv/modules/gui/controlflow/eventhooks.c
index 516a4d2..314357d 100644
--- a/lttv/modules/gui/controlflow/eventhooks.c
+++ b/lttv/modules/gui/controlflow/eventhooks.c
@@ -241,6 +241,8 @@ static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
       prop_line.color = drawing_colors[COL_RUN_USER_MODE];
     else if(process->state->t == LTTV_STATE_SYSCALL)
       prop_line.color = drawing_colors[COL_RUN_SYSCALL];
+    else if(process->state->t == LTTV_STATE_VIRT)
+      prop_line.color = drawing_colors[COL_RUN_VIRT];
     else if(process->state->t == LTTV_STATE_TRAP)
       prop_line.color = drawing_colors[COL_RUN_TRAP];
     else if(process->state->t == LTTV_STATE_IRQ)
-- 
1.7.0.4





More information about the lttng-dev mailing list