提交 48151859 编写于 作者: L Lluís Vilanova 提交者: Stefan Hajnoczi

trace: Add per-vCPU tracing states for events with the 'vcpu' property

Each vCPU gets a 'trace_dstate' bitmap to control the per-vCPU dynamic
tracing state of events with the 'vcpu' property.
Signed-off-by: NLluís Vilanova <vilanova@ac.upc.edu>
Signed-off-by: NStefan Hajnoczi <stefanha@redhat.com>
上级 e1d6e0a4
...@@ -1131,6 +1131,7 @@ int main(int argc, char **argv) ...@@ -1131,6 +1131,7 @@ int main(int argc, char **argv)
gdbserver_start (gdbstub_port); gdbserver_start (gdbstub_port);
gdb_handlesig(cpu, 0); gdb_handlesig(cpu, 0);
} }
trace_init_vcpu_events();
cpu_loop(env); cpu_loop(env);
/* never exits */ /* never exits */
return 0; return 0;
......
...@@ -24,8 +24,10 @@ ...@@ -24,8 +24,10 @@
#include "disas/bfd.h" #include "disas/bfd.h"
#include "exec/hwaddr.h" #include "exec/hwaddr.h"
#include "exec/memattrs.h" #include "exec/memattrs.h"
#include "qemu/bitmap.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu/thread.h" #include "qemu/thread.h"
#include "trace/generated-events.h"
typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
void *opaque); void *opaque);
...@@ -280,6 +282,7 @@ struct qemu_work_item { ...@@ -280,6 +282,7 @@ struct qemu_work_item {
* @kvm_fd: vCPU file descriptor for KVM. * @kvm_fd: vCPU file descriptor for KVM.
* @work_mutex: Lock to prevent multiple access to queued_work_*. * @work_mutex: Lock to prevent multiple access to queued_work_*.
* @queued_work_first: First asynchronous work pending. * @queued_work_first: First asynchronous work pending.
* @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).
* *
* State of one CPU core or thread. * State of one CPU core or thread.
*/ */
...@@ -347,6 +350,9 @@ struct CPUState { ...@@ -347,6 +350,9 @@ struct CPUState {
struct KVMState *kvm_state; struct KVMState *kvm_state;
struct kvm_run *kvm_run; struct kvm_run *kvm_run;
/* Used for events with 'vcpu' and *without* the 'disabled' properties */
DECLARE_BITMAP(trace_dstate, TRACE_VCPU_EVENT_COUNT);
/* TODO Move common fields from CPUArchState here. */ /* TODO Move common fields from CPUArchState here. */
int cpu_index; /* used by alpha TCG */ int cpu_index; /* used by alpha TCG */
uint32_t halted; /* used by alpha, cris, ppc TCG */ uint32_t halted; /* used by alpha, cris, ppc TCG */
......
...@@ -4810,6 +4810,7 @@ int main(int argc, char **argv, char **envp) ...@@ -4810,6 +4810,7 @@ int main(int argc, char **argv, char **envp)
} }
gdb_handlesig(cpu, 0); gdb_handlesig(cpu, 0);
} }
trace_init_vcpu_events();
cpu_loop(env); cpu_loop(env);
/* never exits */ /* never exits */
return 0; return 0;
......
...@@ -345,6 +345,7 @@ static void cpu_common_initfn(Object *obj) ...@@ -345,6 +345,7 @@ static void cpu_common_initfn(Object *obj)
qemu_mutex_init(&cpu->work_mutex); qemu_mutex_init(&cpu->work_mutex);
QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->breakpoints);
QTAILQ_INIT(&cpu->watchpoints); QTAILQ_INIT(&cpu->watchpoints);
bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT);
} }
static void cpu_common_finalize(Object *obj) static void cpu_common_finalize(Object *obj)
......
...@@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o ...@@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o stub-obj-y += slirp.o
stub-obj-y += sysbus.o stub-obj-y += sysbus.o
stub-obj-y += trace-control.o
stub-obj-y += uuid.o stub-obj-y += uuid.o
stub-obj-y += vm-stop.o stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o stub-obj-y += vmstate.o
......
/*
* Interface for configuring and controlling the state of tracing events.
*
* Copyright (C) 2014-2016 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "trace/control.h"
void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
TraceEventID id;
assert(trace_event_get_state_static(ev));
id = trace_event_get_id(ev);
trace_events_enabled_count += state - trace_events_dstate[id];
trace_events_dstate[id] = state;
}
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state)
{
/* should never be called on non-target binaries */
abort();
}
...@@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%) ...@@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%)
# Auto-generated event descriptions for LTTng ust code # Auto-generated event descriptions for LTTng ust code
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
$(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp $(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@ @cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
...@@ -33,6 +34,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) ...@@ -33,6 +34,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
$(obj)/generated-events.h: $(obj)/generated-ust-provider.h $(obj)/generated-events.h: $(obj)/generated-ust-provider.h
$(obj)/generated-events.c: $(obj)/generated-ust.c $(obj)/generated-events.c: $(obj)/generated-ust.c
endif endif
###################################################################### ######################################################################
...@@ -91,6 +93,7 @@ $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers. ...@@ -91,6 +93,7 @@ $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.
# but that gets picked up by QEMU's Makefile as an external dependency # but that gets picked up by QEMU's Makefile as an external dependency
# rule file. So we use '.dtrace' instead # rule file. So we use '.dtrace' instead
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp $(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@ @cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y) $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y)
...@@ -155,4 +158,5 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o ...@@ -155,4 +158,5 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o
util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o
util-obj-$(CONFIG_TRACE_UST) += generated-ust.o util-obj-$(CONFIG_TRACE_UST) += generated-ust.o
util-obj-y += control.o util-obj-y += control.o
target-obj-y += control-target.o
util-obj-y += qmp.o util-obj-y += qmp.o
...@@ -10,8 +10,13 @@ ...@@ -10,8 +10,13 @@
#ifndef TRACE__CONTROL_INTERNAL_H #ifndef TRACE__CONTROL_INTERNAL_H
#define TRACE__CONTROL_INTERNAL_H #define TRACE__CONTROL_INTERNAL_H
#include <stddef.h> /* size_t */
#include "qom/cpu.h"
extern TraceEvent trace_events[]; extern TraceEvent trace_events[];
extern bool trace_events_dstate[]; extern uint16_t trace_events_dstate[];
extern int trace_events_enabled_count; extern int trace_events_enabled_count;
...@@ -74,13 +79,24 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev) ...@@ -74,13 +79,24 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev)
return trace_event_get_state_dynamic_by_id(id); return trace_event_get_state_dynamic_by_id(id);
} }
static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu,
TraceEventVCPUID id)
{ {
int id = trace_event_get_id(ev); /* it's on fast path, avoid consistency checks (asserts) */
assert(ev != NULL); if (unlikely(trace_events_enabled_count)) {
assert(trace_event_get_state_static(ev)); return test_bit(id, vcpu->trace_dstate);
trace_events_enabled_count += state - trace_events_dstate[id]; } else {
trace_events_dstate[id] = state; return false;
}
}
static inline bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev)
{
TraceEventVCPUID id;
assert(trace_event_is_vcpu(ev));
id = trace_event_get_vcpu_id(ev);
return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, id);
} }
#endif /* TRACE__CONTROL_INTERNAL_H */ #endif /* TRACE__CONTROL_INTERNAL_H */
/*
* Interface for configuring and controlling the state of tracing events.
*
* Copyright (C) 2014-2016 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "trace/control.h"
#include "translate-all.h"
void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
CPUState *vcpu;
assert(trace_event_get_state_static(ev));
if (trace_event_is_vcpu(ev)) {
CPU_FOREACH(vcpu) {
trace_event_set_vcpu_state_dynamic(vcpu, ev, state);
}
} else {
TraceEventID id = trace_event_get_id(ev);
trace_events_enabled_count += state - trace_events_dstate[id];
trace_events_dstate[id] = state;
}
}
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state)
{
TraceEventID id;
TraceEventVCPUID vcpu_id;
bool state_pre;
assert(trace_event_get_state_static(ev));
assert(trace_event_is_vcpu(ev));
id = trace_event_get_id(ev);
vcpu_id = trace_event_get_vcpu_id(ev);
state_pre = test_bit(vcpu_id, vcpu->trace_dstate);
if (state_pre != state) {
if (state) {
trace_events_enabled_count++;
set_bit(vcpu_id, vcpu->trace_dstate);
trace_events_dstate[id]++;
} else {
trace_events_enabled_count--;
clear_bit(vcpu_id, vcpu->trace_dstate);
trace_events_dstate[id]--;
}
}
}
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* Copyright (C) 2011-2014 Lluís Vilanova <vilanova@ac.upc.edu> * Copyright (C) 2011-2016 Lluís Vilanova <vilanova@ac.upc.edu>
* *
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
...@@ -25,7 +25,14 @@ ...@@ -25,7 +25,14 @@
#include "monitor/monitor.h" #include "monitor/monitor.h"
int trace_events_enabled_count; int trace_events_enabled_count;
bool trace_events_dstate[TRACE_EVENT_COUNT]; /*
* Interpretation depends on wether the event has the 'vcpu' property:
* - false: Boolean value indicating whether the event is active.
* - true : Integral counting the number of vCPUs that have this event enabled.
*/
uint16_t trace_events_dstate[TRACE_EVENT_COUNT];
/* Marks events for late vCPU state init */
static bool trace_events_dstate_init[TRACE_EVENT_COUNT];
QemuOptsList qemu_trace_opts = { QemuOptsList qemu_trace_opts = {
.name = "trace", .name = "trace",
...@@ -135,7 +142,10 @@ static void do_trace_enable_events(const char *line_buf) ...@@ -135,7 +142,10 @@ static void do_trace_enable_events(const char *line_buf)
TraceEvent *ev = NULL; TraceEvent *ev = NULL;
while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
if (trace_event_get_state_static(ev)) { if (trace_event_get_state_static(ev)) {
/* start tracing */
trace_event_set_state_dynamic(ev, enable); trace_event_set_state_dynamic(ev, enable);
/* mark for late vCPU init */
trace_events_dstate_init[ev->id] = true;
} }
} }
} else { } else {
...@@ -147,7 +157,10 @@ static void do_trace_enable_events(const char *line_buf) ...@@ -147,7 +157,10 @@ static void do_trace_enable_events(const char *line_buf)
error_report("WARNING: trace event '%s' is not traceable", error_report("WARNING: trace event '%s' is not traceable",
line_ptr); line_ptr);
} else { } else {
/* start tracing */
trace_event_set_state_dynamic(ev, enable); trace_event_set_state_dynamic(ev, enable);
/* mark for late vCPU init */
trace_events_dstate_init[ev->id] = true;
} }
} }
} }
...@@ -257,3 +270,15 @@ char *trace_opt_parse(const char *optarg) ...@@ -257,3 +270,15 @@ char *trace_opt_parse(const char *optarg)
return trace_file; return trace_file;
} }
void trace_init_vcpu_events(void)
{
TraceEvent *ev = NULL;
while ((ev = trace_event_pattern("*", ev)) != NULL) {
if (trace_event_is_vcpu(ev) &&
trace_event_get_state_static(ev) &&
trace_events_dstate_init[ev->id]) {
trace_event_set_state_dynamic(ev, true);
}
}
}
...@@ -123,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev); ...@@ -123,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev);
#define trace_event_get_state(id) \ #define trace_event_get_state(id) \
((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id)) ((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id))
/**
* trace_event_get_vcpu_state:
* @vcpu: Target vCPU.
* @id: Event identifier (TraceEventID).
* @vcpu_id: Per-vCPU event identifier (TraceEventVCPUID).
*
* Get the tracing state of an event (both static and dynamic) for the given
* vCPU.
*
* If the event has the disabled property, the check will have no performance
* impact.
*
* As a down side, you must always use an immediate #TraceEventID value.
*/
#define trace_event_get_vcpu_state(vcpu, id, vcpu_id) \
((id ##_ENABLED) && trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id))
/** /**
* trace_event_get_state_static: * trace_event_get_state_static:
* @id: Event identifier. * @id: Event identifier.
...@@ -138,9 +155,18 @@ static bool trace_event_get_state_static(TraceEvent *ev); ...@@ -138,9 +155,18 @@ static bool trace_event_get_state_static(TraceEvent *ev);
* trace_event_get_state_dynamic: * trace_event_get_state_dynamic:
* *
* Get the dynamic tracing state of an event. * Get the dynamic tracing state of an event.
*
* If the event has the 'vcpu' property, gets the OR'ed state of all vCPUs.
*/ */
static bool trace_event_get_state_dynamic(TraceEvent *ev); static bool trace_event_get_state_dynamic(TraceEvent *ev);
/**
* trace_event_get_vcpu_state_dynamic:
*
* Get the dynamic tracing state of an event for the given vCPU.
*/
static bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev);
/** /**
* trace_event_set_state: * trace_event_set_state:
* *
...@@ -154,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); ...@@ -154,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev);
} \ } \
} while (0) } while (0)
/**
* trace_event_set_vcpu_state:
*
* Set the tracing state of an event for the given vCPU (only if not disabled).
*/
#define trace_event_set_vcpu_state(vcpu, id, state) \
do { \
if ((id ##_ENABLED)) { \
TraceEvent *_e = trace_event_id(id); \
trace_event_set_vcpu_state_dynamic(vcpu, _e, state); \
} \
} while (0)
/** /**
* trace_event_set_state_dynamic: * trace_event_set_state_dynamic:
* *
* Set the dynamic tracing state of an event. * Set the dynamic tracing state of an event.
* *
* If the event has the 'vcpu' property, sets the state on all vCPUs.
*
* Pre-condition: trace_event_get_state_static(ev) == true * Pre-condition: trace_event_get_state_static(ev) == true
*/ */
static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); void trace_event_set_state_dynamic(TraceEvent *ev, bool state);
/**
* trace_event_set_vcpu_state_dynamic:
*
* Set the dynamic tracing state of an event for the given vCPU.
*
* Pre-condition: trace_event_get_vcpu_state_static(ev) == true
*/
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state);
...@@ -218,6 +269,15 @@ extern QemuOptsList qemu_trace_opts; ...@@ -218,6 +269,15 @@ extern QemuOptsList qemu_trace_opts;
*/ */
char *trace_opt_parse(const char *optarg); char *trace_opt_parse(const char *optarg);
/**
* trace_init_vcpu_events:
*
* Re-synchronize initial event state with vCPUs (which can be created after
* trace_init_events()).
*/
void trace_init_vcpu_events(void);
#include "trace/control-internal.h" #include "trace/control-internal.h"
#endif /* TRACE__CONTROL_H */ #endif /* TRACE__CONTROL_H */
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#ifndef TRANSLATE_ALL_H #ifndef TRANSLATE_ALL_H
#define TRANSLATE_ALL_H #define TRANSLATE_ALL_H
#include "exec/exec-all.h"
/* translate-all.c */ /* translate-all.c */
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
......
...@@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp) ...@@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp)
os_setup_post(); os_setup_post();
trace_init_vcpu_events();
main_loop(); main_loop();
replay_disable_events(); replay_disable_events();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册