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:
parent
e1d6e0a4c0
commit
4815185902
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
28
stubs/trace-control.c
Normal 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();
|
||||
}
|
@ -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
|
||||
|
@ -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
53
trace/control-target.c
Normal 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]--;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user