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 <[email protected]> --- 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 _______________________________________________ ltt-dev mailing list [email protected] http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
