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: Lluís Vilanova <vilanova@ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Lluís Vilanova 2016-07-11 12:53:41 +02:00 committed by Stefan Hajnoczi
parent e1d6e0a4c0
commit 4815185902
13 changed files with 210 additions and 10 deletions

View File

@ -1131,6 +1131,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;

View File

@ -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);
@ -280,6 +282,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.
*/
@ -347,6 +350,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 */

View File

@ -4810,6 +4810,7 @@ int main(int argc, char **argv, char **envp)
}
gdb_handlesig(cpu, 0);
}
trace_init_vcpu_events();
cpu_loop(env);
/* never exits */
return 0;

View File

@ -345,6 +345,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)

View File

@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o
stub-obj-y += sysbus.o
stub-obj-y += trace-control.o
stub-obj-y += uuid.o
stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o

28
stubs/trace-control.c Normal file
View File

@ -0,0 +1,28 @@
/*
* 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();
}

View File

@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%)
# Auto-generated event descriptions for LTTng ust code
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
$(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(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)
$(obj)/generated-events.h: $(obj)/generated-ust-provider.h
$(obj)/generated-events.c: $(obj)/generated-ust.c
endif
######################################################################
@ -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
# rule file. So we use '.dtrace' instead
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(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
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
util-obj-y += qmp.o

View File

@ -10,8 +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 uint16_t trace_events_dstate[];
extern int trace_events_enabled_count;
@ -74,13 +79,24 @@ 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_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu,
TraceEventVCPUID id)
{
int id = trace_event_get_id(ev);
assert(ev != NULL);
assert(trace_event_get_state_static(ev));
trace_events_enabled_count += state - trace_events_dstate[id];
trace_events_dstate[id] = state;
/* it's on fast path, avoid consistency checks (asserts) */
if (unlikely(trace_events_enabled_count)) {
return test_bit(id, vcpu->trace_dstate);
} else {
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 */

53
trace/control-target.c Normal file
View File

@ -0,0 +1,53 @@
/*
* 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]--;
}
}
}

View File

@ -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.
@ -25,7 +25,14 @@
#include "monitor/monitor.h"
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 = {
.name = "trace",
@ -135,7 +142,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 {
@ -147,7 +157,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;
}
}
}
@ -257,3 +270,15 @@ char *trace_opt_parse(const char *optarg)
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);
}
}
}

View File

@ -123,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev);
#define trace_event_get_state(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:
* @id: Event identifier.
@ -138,9 +155,18 @@ 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_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:
*
@ -154,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev);
} \
} 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:
*
* 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_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;
*/
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"
#endif /* TRACE__CONTROL_H */

View File

@ -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,

1
vl.c
View File

@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp)
os_setup_post();
trace_init_vcpu_events();
main_loop();
replay_disable_events();