[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCHv18/8] trace: [tcg] Add per-vCPU tracing states for e
From: |
Lluís Vilanova |
Subject: |
[Qemu-devel] [PATCHv18/8] trace: [tcg] Add per-vCPU tracing states for events with the 'vcpu' property |
Date: |
Tue, 13 Oct 2015 19:11:07 +0200 |
User-agent: |
StGit/0.17.1-dirty |
Signed-off-by: Lluís Vilanova <address@hidden>
---
Makefile.objs | 1
include/qom/cpu.h | 5 +
qapi/trace.json | 31 +++++++
qmp-commands.hx | 27 ++++++
qom/cpu.c | 12 +++
scripts/tracetool/format/tcg_h.py | 6 +
scripts/tracetool/format/tcg_helper_c.py | 11 ++-
trace/Makefile.objs | 2
trace/control-internal.h | 17 +++-
trace/control-stub.c | 29 +++++++
trace/control-target.c | 53 +++++++++++++
trace/control.h | 53 ++++++++++++-
trace/qmp.c | 127 ++++++++++++++++++++++++++++--
translate-all.c | 1
ui/Makefile.objs | 2
15 files changed, 357 insertions(+), 20 deletions(-)
create mode 100644 trace/control-stub.c
create mode 100644 trace/control-target.c
diff --git a/Makefile.objs b/Makefile.objs
index e1d7b25..99f9d2a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -100,6 +100,7 @@ version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
# tracing
util-obj-y += trace/
target-obj-y += trace/
+stub-obj-y += trace/
######################################################################
# guest agent
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 743e13b..94a4c1d 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -29,6 +29,7 @@
#include "qemu/queue.h"
#include "qemu/thread.h"
#include "qemu/typedefs.h"
+#include "trace/generated-events.h"
typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
void *opaque);
@@ -316,6 +317,10 @@ struct CPUState {
unsigned int tb_phys_idx;
unsigned int tb_phys_idx_req;
+ /* Ensure 'tb_phys_idx' can encode event states as a bitmask */
+ bool too_many_tcg_vcpu_events[
+ TRACE_CPU_EVENT_COUNT > sizeof(unsigned int)*8 ? -1 : 0];
+
/* TODO Move common fields from CPUArchState here. */
int cpu_index; /* used by alpha TCG */
uint32_t halted; /* used by alpha, cris, ppc TCG */
diff --git a/qapi/trace.json b/qapi/trace.json
index 94a3a3b..369f4aa 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -64,3 +64,34 @@
##
{ 'command': 'trace-event-set-state',
'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool'} }
+
+##
+# @trace-event-get-cpu-state:
+#
+# Query the state of events in a given vCPU.
+#
+# @name: Event name pattern.
+# @vcpu: The vCPU to check.
+#
+# Returns: @TraceEventInfo of the matched events
+#
+# Since 2.2
+##
+{ 'command': 'trace-event-get-cpu-state',
+ 'data': {'name': 'str', 'vcpu': 'int'},
+ 'returns': ['TraceEventInfo'] }
+
+##
+# @trace-event-set-cpu-state:
+#
+# Set the dynamic state of events in a given vCPU.
+#
+# @name: Event name pattern.
+# @vcpu: The vCPU to act upon.
+# @enable: Whether to enable tracing.
+# @ignore-unavailable: #optional Do not match unavailable events with @name.
+#
+# Since 2.2
+##
+{ 'command': 'trace-event-set-cpu-state',
+ 'data': {'name': 'str', 'vcpu': 'int', 'enable': 'bool',
'*ignore-unavailable': 'bool'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d2ba800..b6b55af 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4189,6 +4189,33 @@ Move mouse pointer to absolute coordinates (20000, 400).
{ "type": "abs", "data" : { "axis": "X", "value" : 20000 } },
{ "type": "abs", "data" : { "axis": "Y", "value" : 400 } } ] } }
<- { "return": {} }
+EQMP
+
+ {
+ .name = "trace-event-get-cpu-state",
+ .args_type = "name:s,vcpu:i",
+ .mhandler.cmd_new = qmp_marshal_trace_event_get_cpu_state,
+ },
+
+SQMP
+trace-event-get-state
+---------------------
+
+Query the state of events in a given vCPU.
+
+EQMP
+
+ {
+ .name = "trace-event-set-cpu-state",
+ .args_type = "name:s,vcpu:i,enable:b,ignore-unavailable:b?",
+ .mhandler.cmd_new = qmp_marshal_trace_event_set_cpu_state,
+ },
+
+SQMP
+trace-event-set-state
+---------------------
+
+Set the state of events in a given vCPU.
EQMP
diff --git a/qom/cpu.c b/qom/cpu.c
index bb7a618..bc27381 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -25,6 +25,7 @@
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
+#include "trace/control.h"
bool cpu_exists(int64_t id)
{
@@ -227,6 +228,17 @@ void cpu_dump_statistics(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf,
void cpu_reset(CPUState *cpu)
{
CPUClass *klass = CPU_GET_CLASS(cpu);
+ TraceEvent *ev = NULL;
+
+ if (!qemu_initialized) {
+ /* trace enabled events on all initial vCPUs */
+ while ((ev = trace_event_pattern("*", ev)) != NULL) {
+ if (trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT &&
+ trace_event_get_state_dynamic(ev)) {
+ trace_event_set_state_dynamic(ev, true);
+ }
+ }
+ }
if (klass->reset != NULL) {
(*klass->reset)(cpu);
diff --git a/scripts/tracetool/format/tcg_h.py
b/scripts/tracetool/format/tcg_h.py
index 222002c..7a9254f 100644
--- a/scripts/tracetool/format/tcg_h.py
+++ b/scripts/tracetool/format/tcg_h.py
@@ -52,7 +52,11 @@ def generate(events, backend):
if "disable" not in e.properties:
out(' %(name_trans)s(%(argnames_trans)s);',
- ' gen_helper_%(name_exec)s(%(argnames_exec)s);',
+ ' if (%(cond)s) {',
+ ' gen_helper_%(name_exec)s(%(argnames_exec)s);',
+ ' }',
+ cond='trace_event_get_cpu_state(_cpu, TRACE_%s_TRANS)' %
e.name.upper()
+ if "vcpu" in e.properties else "true",
name_trans=e.event_trans.api(e.QEMU_TRACE),
name_exec=e.event_exec.api(e.QEMU_TRACE),
argnames_trans=", ".join(e.event_trans.args.names()),
diff --git a/scripts/tracetool/format/tcg_helper_c.py
b/scripts/tracetool/format/tcg_helper_c.py
index 96655a0..0cb7f45 100644
--- a/scripts/tracetool/format/tcg_helper_c.py
+++ b/scripts/tracetool/format/tcg_helper_c.py
@@ -6,7 +6,7 @@ Generate trace/generated-helpers.c.
"""
__author__ = "Lluís Vilanova <address@hidden>"
-__copyright__ = "Copyright 2012-2014, Lluís Vilanova <address@hidden>"
+__copyright__ = "Copyright 2012-2015, Lluís Vilanova <address@hidden>"
__license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi"
@@ -36,8 +36,13 @@ def generate(events, backend):
# tracetool.generate always transforms types to host
e_args = e.original.args
- values = ["(%s)%s" % (t, n)
- for t, n in e.args.transform(TCG_2_TCG_HELPER_DEF)]
+ values = []
+ for (t_old, n), (t_new, _) in zip(
+ e.args, e.args.transform(TCG_2_TCG_HELPER_DEF)):
+ if t_old == "CPUState *":
+ values.append("ENV_GET_CPU((CPUArchState*)%s)" % n)
+ else:
+ values.append("(%s)%s" % (t_new, n))
out('void %(name_tcg)s(%(args)s)',
'{',
diff --git a/trace/Makefile.objs b/trace/Makefile.objs
index 32f7a32..15896de 100644
--- a/trace/Makefile.objs
+++ b/trace/Makefile.objs
@@ -144,4 +144,6 @@ 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
diff --git a/trace/control-internal.h b/trace/control-internal.h
index 70e55df..b4069e3 100644
--- a/trace/control-internal.h
+++ b/trace/control-internal.h
@@ -12,6 +12,12 @@
#include <string.h>
+#include "qemu-common.h"
+/* GTK headers conflict with QOM's '_' */
+#if !defined(TRACE_CPU_INCLUDE_HACK)
+#include "qom/cpu.h"
+#endif
+
extern TraceEvent trace_events[];
@@ -63,11 +69,16 @@ static inline bool trace_event_get_state_dynamic(TraceEvent
*ev)
return ev->dstate;
}
-static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
+static inline bool trace_event_get_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev)
{
+#if !defined(TRACE_CPU_INCLUDE_HACK)
+ assert(cpu != NULL);
assert(ev != NULL);
- assert(trace_event_get_state_static(ev));
- ev->dstate = state;
+ return cpu->tb_phys_idx & (((unsigned long)1) << ev->cpu_id);
+#else
+ abort();
+#endif
}
#endif /* TRACE__CONTROL_INTERNAL_H */
diff --git a/trace/control-stub.c b/trace/control-stub.c
new file mode 100644
index 0000000..dd62d3b
--- /dev/null
+++ b/trace/control-stub.c
@@ -0,0 +1,29 @@
+/*
+ * Interface for configuring and controlling the state of tracing events.
+ *
+ * Copyright (C) 2014-2015 Lluís Vilanova <address@hidden>
+ *
+ * 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 "trace/control.h"
+
+
+void trace_init_vcpu_tb_caches(void)
+{
+}
+
+void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
+{
+ assert(ev != NULL);
+ assert(trace_event_get_state_static(ev));
+ ev->dstate = state;
+}
+
+void trace_event_set_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev, bool state)
+{
+ /* should never be called on non-target binaries */
+ abort();
+}
diff --git a/trace/control-target.c b/trace/control-target.c
new file mode 100644
index 0000000..84d3243
--- /dev/null
+++ b/trace/control-target.c
@@ -0,0 +1,53 @@
+/*
+ * Interface for configuring and controlling the state of tracing events.
+ *
+ * Copyright (C) 2014-2015 Lluís Vilanova <address@hidden>
+ *
+ * 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 "trace/control.h"
+#include "cpu.h"
+#include "translate-all.h"
+
+
+void trace_init_vcpu_tb_caches(void)
+{
+ unsigned int events = 1;
+ TraceEvent *ev = NULL;
+ while ((ev = trace_event_pattern("*", ev)) != NULL) {
+ if (trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) {
+ continue;
+ }
+ events <<= 1;
+ }
+ tb_caches_set(events);
+ tb_caches_apply();
+}
+
+void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
+{
+ CPUState *cpu;
+ assert(ev != NULL);
+ assert(trace_event_get_state_static(ev));
+ CPU_FOREACH(cpu) {
+ trace_event_set_cpu_state_dynamic(cpu, ev, state);
+ }
+ ev->dstate = state;
+}
+
+void trace_event_set_cpu_state_dynamic(CPUState *cpu,
+ TraceEvent *ev, bool state)
+{
+ unsigned int bit;
+ assert(cpu != NULL);
+ assert(ev != NULL);
+ assert(trace_event_get_state_static(ev));
+ assert(trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT);
+ if (state) {
+ ev->dstate = state;
+ }
+ bit = ((unsigned long)1) << ev->cpu_id;
+ cpu_tb_cache_set(cpu, (cpu_tb_cache_get(cpu) & ~bit) | bit);
+}
diff --git a/trace/control.h b/trace/control.h
index c0680c7..be3864a 100644
--- a/trace/control.h
+++ b/trace/control.h
@@ -13,7 +13,8 @@
#include "qemu-common.h"
#include "trace/generated-events.h"
-
+/* Forward declaration */
+struct CPUState;
typedef struct CPUState CPUState;
@@ -117,6 +118,22 @@ static const char * trace_event_get_name(TraceEvent *ev);
((id ##_ENABLED) && trace_event_get_state_dynamic(trace_event_id(id)))
/**
+ * trace_event_get_cpu_state:
+ * @id: Event identifier.
+ *
+ * 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) \
+ ((id ##_ENABLED) && trace_event_get_cpu_state_dynamic(cpu, \
+ trace_event_id(id)))
+
+/**
* trace_event_get_state_static:
* @id: Event identifier.
*
@@ -135,6 +152,13 @@ static bool trace_event_get_state_static(TraceEvent *ev);
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 +172,36 @@ 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 possible).
+ */
+#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.
*
* 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);
@@ -171,6 +218,8 @@ static void trace_event_set_state_dynamic(TraceEvent *ev,
bool state);
*/
bool trace_init_backends(const char *events, const char *file);
+void trace_init_vcpu_tb_caches(void);
+
#include "trace/control-internal.h"
diff --git a/trace/qmp.c b/trace/qmp.c
index a669698..9515a91 100644
--- a/trace/qmp.c
+++ b/trace/qmp.c
@@ -1,7 +1,7 @@
/*
* QMP commands for tracing events.
*
- * Copyright (C) 2014 Lluís Vilanova <address@hidden>
+ * Copyright (C) 2014-2015 Lluís Vilanova <address@hidden>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -44,34 +44,141 @@ TraceEventInfoList *qmp_trace_event_get_state(const char
*name, Error **errp)
return events;
}
+
+static void check_events_are_dynamic(const char *name, bool per_cpu,
+ bool *found, bool error_check,
+ bool *error_found, Error **errp)
+{
+ TraceEvent *ev = NULL;
+ *found = false;
+ *error_found = false;
+ while ((ev = trace_event_pattern(name, ev)) != NULL) {
+ if (per_cpu && trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) {
+ continue;
+ }
+ *found = true;
+ if (!trace_event_get_state_static(ev)) {
+ if (error_check) {
+ error_setg(
+ errp, "cannot set dynamic tracing state for \"%s\"\n",
+ trace_event_get_name(ev));
+ *error_found = true;
+ return;
+ }
+ }
+ }
+}
+
void qmp_trace_event_set_state(const char *name, bool enable,
bool has_ignore_unavailable,
bool ignore_unavailable, Error **errp)
{
+ bool error, found;
+ TraceEvent *ev = NULL;
+
+ /* Check all selected events are dynamic */
+ check_events_are_dynamic(name, false, &found,
+ !(has_ignore_unavailable && ignore_unavailable),
+ &error, errp);
+ if (error) {
+ return;
+ }
+ if (!found && !trace_event_is_pattern(name)) {
+ error_setg(errp, "unknown event \"%s\"\n", name);
+ return;
+ }
+
+ /* Apply changes */
+ ev = NULL;
+ while ((ev = trace_event_pattern(name, ev)) != NULL) {
+ if (trace_event_get_state_static(ev)) {
+ trace_event_set_state_dynamic(ev, enable);
+ }
+ }
+}
+
+
+static CPUState *get_cpu_state(int index, Error **errp)
+{
+ CPUState *cpu = qemu_get_cpu(index);
+ if (cpu == NULL) {
+ error_setg(errp, "invalid vCPU index %u\n", index);
+ }
+ return cpu;
+}
+
+TraceEventInfoList *qmp_trace_event_get_cpu_state(const char *name,
+ int64_t vcpu, Error **errp)
+{
+ TraceEventInfoList *events = NULL;
bool found = false;
TraceEvent *ev;
+ CPUState *cpu = get_cpu_state(vcpu, errp);
+ if (!cpu) {
+ return NULL;
+ }
- /* Check all selected events are dynamic */
ev = NULL;
while ((ev = trace_event_pattern(name, ev)) != NULL) {
- found = true;
- if (!(has_ignore_unavailable && ignore_unavailable) &&
- !trace_event_get_state_static(ev)) {
- error_setg(errp, "cannot set dynamic tracing state for \"%s\"",
- trace_event_get_name(ev));
- return;
+ TraceEventInfoList *elem;
+ if (trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) {
+ continue;
}
+ elem = g_new(TraceEventInfoList, 1);
+ elem->value = g_new(TraceEventInfo, 1);
+ elem->value->vcpu =
+ trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT ? false : true;
+ elem->value->name = g_strdup(trace_event_get_name(ev));
+ if (!trace_event_get_state_static(ev)) {
+ elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
+ } else if (!trace_event_get_state_dynamic(ev)) {
+ elem->value->state = TRACE_EVENT_STATE_DISABLED;
+ } else {
+ elem->value->state = TRACE_EVENT_STATE_ENABLED;
+ }
+ elem->next = events;
+ events = elem;
+ found = true;
}
+
if (!found && !trace_event_is_pattern(name)) {
- error_setg(errp, "unknown event \"%s\"", name);
+ error_setg(errp, "unknown or non-vCPU event \"%s\"\n", name);
+ }
+
+ return events;
+}
+
+void qmp_trace_event_set_cpu_state(const char *name, int64_t vcpu, bool enable,
+ bool has_ignore_unavailable,
+ bool ignore_unavailable, Error **errp)
+{
+ bool error, found;
+ TraceEvent *ev = NULL;
+ CPUState *cpu = get_cpu_state(vcpu, errp);
+ if (!cpu) {
+ return;
+ }
+
+ /* Check all selected events are dynamic */
+ check_events_are_dynamic(name, true, &found,
+ !(has_ignore_unavailable && ignore_unavailable),
+ &error, errp);
+ if (error) {
+ return;
+ }
+ if (!found && !trace_event_is_pattern(name)) {
+ error_setg(errp, "unknown or non-vCPU event \"%s\"\n", name);
return;
}
/* Apply changes */
ev = NULL;
while ((ev = trace_event_pattern(name, ev)) != NULL) {
+ if (trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) {
+ continue;
+ }
if (trace_event_get_state_static(ev)) {
- trace_event_set_state_dynamic(ev, enable);
+ trace_event_set_cpu_state_dynamic(cpu, ev, enable);
}
}
}
diff --git a/translate-all.c b/translate-all.c
index 5ae64d6..4e4c8e2 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -179,6 +179,7 @@ void cpu_gen_init(void)
tcg_ctx.tb_ctx.tb_phys_hash_size_req = 1;
tcg_ctx.tb_ctx.tb_phys_hash = NULL;
tb_caches_apply();
+ trace_init_vcpu_tb_caches();
}
/* Encode VAL as a signed leb128 sequence at P.
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 0034fbb..453b482 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -34,7 +34,7 @@ common-obj-y += egl-helpers.o
common-obj-$(CONFIG_GTK) += gtk-egl.o
endif
-gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
+gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) -DTRACE_CPU_INCLUDE_HACK
gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
shader.o-cflags += $(OPENGL_CFLAGS)
console-gl.o-cflags += $(OPENGL_CFLAGS)
- [Qemu-devel] [RFC][PATCHv10/8] trace: Per-vCPU tracing states, Lluís Vilanova, 2015/10/15
- [Qemu-devel] [PATCHv15/8] exec: [ŧcg] Use multiple physical TB caches, Lluís Vilanova, 2015/10/13
- [Qemu-devel] [PATCHv14/8] exec: [tcg] Refactor flush of per-CPU virtual TB cache, Lluís Vilanova, 2015/10/13
- [Qemu-devel] [PATCHv12/8] trace: Add 'vcpu' event property, Lluís Vilanova, 2015/10/13
- [Qemu-devel] [PATCHv18/8] trace: [tcg] Add per-vCPU tracing states for events with the 'vcpu' property,
Lluís Vilanova <=
- [Qemu-devel] [PATCHv17/8] [trivial] Track when QEMU has finished initialization, Lluís Vilanova, 2015/10/13
- [Qemu-devel] [PATCHv16/8] exec: [tcg] Track which vCPU is performing translation and execution, Lluís Vilanova, 2015/10/13
- [Qemu-devel] [PATCHv11/8] trace: Add support for vCPU pointers in trace events, Lluís Vilanova, 2015/10/13