@@ -102,6 +102,7 @@ version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
# tracing
util-obj-y += trace/
target-obj-y += trace/
+stub-obj-y += trace/
######################################################################
# guest agent
@@ -27,6 +27,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "tcg.h"
+#include "trace/control.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "exec/log.h"
@@ -1116,6 +1117,7 @@ int main(int argc, char **argv)
gdbserver_start (gdbstub_port);
gdb_handlesig(cpu, 0);
}
+ trace_init_vcpu_events();
cpu_loop(env);
/* never exits */
return 0;
@@ -24,8 +24,10 @@
#include "disas/bfd.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
+#include "qemu/bitmap.h"
#include "qemu/queue.h"
#include "qemu/thread.h"
+#include "trace/generated-events.h"
typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
void *opaque);
@@ -273,6 +275,7 @@ struct qemu_work_item {
* @kvm_fd: vCPU file descriptor for KVM.
* @work_mutex: Lock to prevent multiple access to queued_work_*.
* @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.
*/
@@ -340,6 +343,9 @@ struct CPUState {
struct KVMState *kvm_state;
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. */
int cpu_index; /* used by alpha TCG */
uint32_t halted; /* used by alpha, cris, ppc TCG */
@@ -29,6 +29,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "tcg.h"
+#include "trace/control.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "elf.h"
@@ -4776,6 +4777,7 @@ int main(int argc, char **argv, char **envp)
}
gdb_handlesig(cpu, 0);
}
+ trace_init_vcpu_events();
cpu_loop(env);
/* never exits */
return 0;
@@ -330,6 +330,7 @@ static void cpu_common_initfn(Object *obj)
qemu_mutex_init(&cpu->work_mutex);
QTAILQ_INIT(&cpu->breakpoints);
QTAILQ_INIT(&cpu->watchpoints);
+ bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT);
}
static void cpu_common_finalize(Object *obj)
@@ -12,6 +12,8 @@ tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py")
# Auto-generated event descriptions for LTTng ust code
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
+
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-ust-provider.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
@@ -30,11 +32,14 @@ $(obj)/generated-ust.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
$(obj)/generated-events.h: $(obj)/generated-ust-provider.h
$(obj)/generated-events.c: $(obj)/generated-ust.c
+endif # MAKEFILE_GUARD_TRACE
+
endif
######################################################################
# Auto-generated event descriptions
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-events.h: $(obj)/generated-events.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-events.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
@@ -50,6 +55,7 @@ $(obj)/generated-events.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y)
--format=events-c \
--backends=$(TRACE_BACKENDS) \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+endif # MAKEFILE_GUARD_TRACE
util-obj-y += generated-events.o
@@ -60,6 +66,7 @@ util-obj-y += generated-events.o
##################################################
# Execution level
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp
@cmp -s $< $@ || cp $< $@
$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
@@ -67,10 +74,12 @@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf
--format=h \
--backends=$(TRACE_BACKENDS) \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+endif # MAKEFILE_GUARD_TRACE
##############################
# non-DTrace
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp
@cmp -s $< $@ || cp $< $@
$(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
@@ -80,6 +89,7 @@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h
+endif # MAKEFILE_GUARD_TRACE
##############################
# DTrace
@@ -88,6 +98,8 @@ $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.
# but that gets picked up by QEMU's Makefile as an external dependency
# rule file. So we use '.dtrace' instead
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
+
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
@@ -100,6 +112,7 @@ $(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@")
$(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace
+endif # MAKEFILE_GUARD_TRACE
util-obj-y += generated-tracers-dtrace.o
endif
@@ -107,6 +120,7 @@ endif
##################################################
# Translation level
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-helpers-wrappers.h: $(obj)/generated-helpers-wrappers.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-helpers-wrappers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
@@ -132,10 +146,12 @@ $(obj)/generated-helpers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
$(obj)/generated-helpers.o: $(obj)/generated-helpers.c
+endif # MAKEFILE_GUARD_TRACE
target-obj-y += generated-helpers.o
+ifndef MAKEFILE_GUARD_TRACE
$(obj)/generated-tcg-tracers.h: $(obj)/generated-tcg-tracers.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-tcg-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(tracetool-y)
@@ -143,6 +159,7 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/
--format=tcg-h \
--backend=$(TRACE_BACKENDS) \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+endif # MAKEFILE_GUARD_TRACE
######################################################################
@@ -152,4 +169,13 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o
util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o
util-obj-$(CONFIG_TRACE_UST) += generated-ust.o
util-obj-y += control.o
+target-obj-y += control-target.o
+stub-obj-y += control-stub.o
util-obj-y += qmp.o
+
+
+######################################################################
+# Avoid rule overrides when included from multiple top-level variables
+ifndef MAKEFILE_GUARD_TRACE
+MAKEFILE_GUARD_TRACE = 1
+endif
@@ -10,10 +10,13 @@
#ifndef TRACE__CONTROL_INTERNAL_H
#define TRACE__CONTROL_INTERNAL_H
+#include <stddef.h> /* size_t */
+
+#include "qom/cpu.h"
extern TraceEvent trace_events[];
-extern bool trace_events_dstate[];
+extern size_t trace_events_dstate[];
extern int trace_events_enabled_count;
@@ -22,6 +25,11 @@ static inline TraceEventID trace_event_count(void)
return TRACE_EVENT_COUNT;
}
+static inline TraceEventVCPUID trace_event_cpu_count(void)
+{
+ return TRACE_VCPU_EVENT_COUNT;
+}
+
static inline TraceEvent *trace_event_id(TraceEventID id)
{
assert(id < trace_event_count());
@@ -61,7 +69,7 @@ static inline bool trace_event_get_state_static(TraceEvent *ev)
static inline bool trace_event_get_state_dynamic_by_id(TraceEventID id)
{
/* it's on fast path, avoid consistency checks (asserts) */
- return unlikely(trace_events_enabled_count) && trace_events_dstate[id];
+ return unlikely(trace_events_enabled_count) && (trace_events_dstate[id] > 0);
}
static inline bool trace_event_get_state_dynamic(TraceEvent *ev)
@@ -73,13 +81,27 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev)
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_cpu_state_dynamic_by_cpu_id(CPUState *cpu,
+ TraceEventVCPUID id)
+{
+ /* it's on fast path, avoid consistency checks (asserts) */
+ if (unlikely(trace_events_enabled_count)) {
+ return test_bit(id, cpu->trace_dstate);
+ } else {
+ return false;
+ }
+}
+
+static inline bool trace_event_get_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev)
{
- int id = trace_event_get_id(ev);
+ TraceEventVCPUID id;
+ assert(cpu != NULL);
assert(ev != NULL);
assert(trace_event_get_state_static(ev));
- trace_events_enabled_count += state - trace_events_dstate[id];
- trace_events_dstate[id] = state;
+ assert(trace_event_get_cpu_id(ev) != trace_event_cpu_count());
+ id = trace_event_get_cpu_id(ev);
+ return trace_event_get_cpu_state_dynamic_by_cpu_id(cpu, id);
}
#endif /* TRACE__CONTROL_INTERNAL_H */
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+ * 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(ev != NULL);
+ 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_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev, bool state)
+{
+ /* should never be called on non-target binaries */
+ abort();
+}
new file mode 100644
@@ -0,0 +1,56 @@
+/*
+ * 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 *cpu;
+ assert(ev != NULL);
+ assert(trace_event_get_state_static(ev));
+ if (trace_event_get_cpu_id(ev) != trace_event_cpu_count()) {
+ CPU_FOREACH(cpu) {
+ trace_event_set_cpu_state_dynamic(cpu, 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_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev, bool state)
+{
+ TraceEventID id;
+ TraceEventVCPUID cpu_id;
+ bool state_pre;
+ assert(cpu != NULL);
+ assert(ev != NULL);
+ assert(trace_event_get_state_static(ev));
+ assert(trace_event_get_cpu_id(ev) != trace_event_cpu_count());
+ id = trace_event_get_id(ev);
+ cpu_id = trace_event_get_cpu_id(ev);
+ state_pre = test_bit(cpu_id, cpu->trace_dstate);
+ if (state_pre != state) {
+ if (state) {
+ trace_events_enabled_count++;
+ set_bit(cpu_id, cpu->trace_dstate);
+ trace_events_dstate[id]++;
+ } else {
+ trace_events_enabled_count--;
+ clear_bit(cpu_id, cpu->trace_dstate);
+ trace_events_dstate[id]--;
+ }
+ }
+}
@@ -1,7 +1,7 @@
/*
* 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.
* See the COPYING file in the top-level directory.
@@ -23,7 +23,16 @@
#include "monitor/monitor.h"
int trace_events_enabled_count;
-bool trace_events_dstate[TRACE_EVENT_COUNT];
+/*
+ * Interpretation depends on TraceEvent::cpu_id:
+ * - == trace_event_cpu_count() [event without 'vcpu' property]:
+ * Boolean value indicating whether the event is active.
+ * - < trace_event_cpu_count() [event with 'vcpu' property]:
+ * Integral counting the number of vCPUs that have this event enabled.
+ */
+size_t trace_events_dstate[TRACE_EVENT_COUNT];
+/* Marks events for late vCPU state init */
+static bool trace_events_dstate_init[TRACE_EVENT_COUNT];
TraceEvent *trace_event_name(const char *name)
{
@@ -112,7 +121,10 @@ static void do_trace_enable_events(const char *line_buf)
TraceEvent *ev = NULL;
while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
if (trace_event_get_state_static(ev)) {
+ /* start tracing */
trace_event_set_state_dynamic(ev, enable);
+ /* mark for late vCPU init */
+ trace_events_dstate_init[ev->id] = true;
}
}
} else {
@@ -124,7 +136,10 @@ static void do_trace_enable_events(const char *line_buf)
error_report("WARNING: trace event '%s' is not traceable",
line_ptr);
} else {
+ /* start tracing */
trace_event_set_state_dynamic(ev, enable);
+ /* mark for late vCPU init */
+ trace_events_dstate_init[ev->id] = true;
}
}
}
@@ -216,3 +231,15 @@ bool trace_init_backends(void)
return true;
}
+
+void trace_init_vcpu_events(void)
+{
+ TraceEvent *ev = NULL;
+ while ((ev = trace_event_pattern("*", ev)) != NULL) {
+ if (trace_event_get_cpu_id(ev) != trace_event_cpu_count() &&
+ trace_event_get_state_static(ev) &&
+ trace_events_dstate_init[ev->id]) {
+ trace_event_set_state_dynamic(ev, true);
+ }
+ }
+}
@@ -76,6 +76,13 @@ static bool trace_event_is_pattern(const char *str);
*/
static TraceEventID trace_event_count(void);
+/**
+ * trace_event_cpu_count:
+ *
+ * Return the number of events with the 'vcpu' property.
+ */
+static TraceEventVCPUID trace_event_cpu_count(void);
+
/**
@@ -117,6 +124,23 @@ static const char * trace_event_get_name(TraceEvent *ev);
((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id))
/**
+ * trace_event_get_cpu_state:
+ * @cpu: Target vCPU.
+ * @id: Event identifier (TraceEventID).
+ * @cpu_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_cpu_state(cpu, id, cpu_id) \
+ ((id ##_ENABLED) && trace_event_get_cpu_state_dynamic_by_cpu_id(cpu, cpu_id))
+
+/**
* trace_event_get_state_static:
* @id: Event identifier.
*
@@ -131,10 +155,19 @@ static bool trace_event_get_state_static(TraceEvent *ev);
* trace_event_get_state_dynamic:
*
* 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);
/**
+ * trace_event_get_cpu_state_dynamic:
+ *
+ * Get the dynamic tracing state of an event for the given vCPU.
+ */
+static bool trace_event_get_cpu_state_dynamic(CPUState *cpu, TraceEvent *ev);
+
+/**
* trace_event_set_state:
*
* Set the tracing state of an event (only if possible).
@@ -148,13 +181,38 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev);
} while (0)
/**
+ * trace_event_set_cpu_state:
+ *
+ * Set the tracing state of an event for the given vCPU (only if not disabled).
+ */
+#define trace_event_set_cpu_state(cpu, id, state) \
+ do { \
+ if ((id ##_ENABLED)) { \
+ TraceEvent *_e = trace_event_id(id); \
+ trace_event_set_cpu_state_dynamic(cpu, _e, state); \
+ } \
+ } while (0)
+
+/**
* trace_event_set_state_dynamic:
*
* 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
*/
-static void trace_event_set_state_dynamic(TraceEvent *ev, bool state);
+void trace_event_set_state_dynamic(TraceEvent *ev, bool state);
+
+/**
+ * trace_event_set_cpu_state_dynamic:
+ *
+ * Set the dynamic tracing state of an event for the given vCPU.
+ *
+ * Pre-condition: trace_event_get_cpu_state_static(ev) == true
+ */
+void trace_event_set_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev, bool state);
@@ -207,6 +265,14 @@ void trace_list_events(void);
*/
void trace_enable_events(const char *line_buf);
+/**
+ * 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"
@@ -19,6 +19,9 @@
#ifndef TRANSLATE_ALL_H
#define TRANSLATE_ALL_H
+#include "exec/exec-all.h"
+
+
/* translate-all.c */
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,
@@ -4624,6 +4624,7 @@ int main(int argc, char **argv, char **envp)
os_setup_post();
+ trace_init_vcpu_events();
main_loop();
replay_disable_events();
Each vCPU gets a 'trace_dstate' bitmap to control the per-vCPU dynamic tracing state of events with the 'vcpu' property. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile.objs | 1 + bsd-user/main.c | 2 + include/qom/cpu.h | 6 ++++ linux-user/main.c | 2 + qom/cpu.c | 1 + trace/Makefile.objs | 26 ++++++++++++++++++ trace/control-internal.h | 34 +++++++++++++++++++---- trace/control-stub.c | 29 ++++++++++++++++++++ trace/control-target.c | 56 ++++++++++++++++++++++++++++++++++++++ trace/control.c | 31 ++++++++++++++++++++- trace/control.h | 68 +++++++++++++++++++++++++++++++++++++++++++++- translate-all.h | 3 ++ vl.c | 1 + 13 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 trace/control-stub.c create mode 100644 trace/control-target.c