qemu-devel
[Top][All Lists]
Advanced

[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)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]