diff options
author | Lluís Vilanova <vilanova@ac.upc.edu> | 2016-07-11 12:53:57 +0200 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2016-07-18 18:23:12 +0100 |
commit | 77e2b17272963c09e309315903f3781dbdd85341 (patch) | |
tree | 3a6041c320317edf40167dd6b69b2912b496e763 /trace/qmp.c | |
parent | bd71211d556aac5451696785fbe29be7f70bed05 (diff) |
trace: Add QAPI/QMP interfaces to query and control per-vCPU tracing state
Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'trace/qmp.c')
-rw-r--r-- | trace/qmp.c | 148 |
1 files changed, 119 insertions, 29 deletions
diff --git a/trace/qmp.c b/trace/qmp.c index 8aa2660aac..11d2564e7b 100644 --- a/trace/qmp.c +++ b/trace/qmp.c @@ -1,7 +1,7 @@ /* * QMP commands for tracing events. * - * Copyright (C) 2014 Lluís Vilanova <vilanova@ac.upc.edu> + * 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. @@ -12,63 +12,153 @@ #include "trace/control.h" -TraceEventInfoList *qmp_trace_event_get_state(const char *name, Error **errp) +static CPUState *get_cpu(bool has_vcpu, int vcpu, Error **errp) { + if (has_vcpu) { + CPUState *cpu = qemu_get_cpu(vcpu); + if (cpu == NULL) { + error_setg(errp, "invalid vCPU index %u", vcpu); + } + return cpu; + } else { + return NULL; + } +} + +static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern, + const char *name, Error **errp) +{ + if (!is_pattern) { + TraceEvent *ev = trace_event_name(name); + + /* error for non-existing event */ + if (ev == NULL) { + error_setg(errp, "unknown event \"%s\"", name); + return false; + } + + /* error for non-vcpu event */ + if (has_vcpu && !trace_event_is_vcpu(ev)) { + error_setg(errp, "event \"%s\" is not vCPU-specific", name); + return false; + } + + /* error for unavailable event */ + if (!ignore_unavailable && !trace_event_get_state_static(ev)) { + error_setg(errp, "event \"%s\" is disabled", name); + return false; + } + + return true; + } else { + /* error for unavailable events */ + TraceEvent *ev = NULL; + while ((ev = trace_event_pattern(name, ev)) != NULL) { + if (!ignore_unavailable && !trace_event_get_state_static(ev)) { + error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev)); + return false; + } + } + return true; + } +} + +TraceEventInfoList *qmp_trace_event_get_state(const char *name, + bool has_vcpu, int64_t vcpu, + Error **errp) +{ + Error *err = NULL; TraceEventInfoList *events = NULL; - bool found = false; TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(name); + CPUState *cpu; + /* Check provided vcpu */ + cpu = get_cpu(has_vcpu, vcpu, &err); + if (err) { + error_propagate(errp, err); + return NULL; + } + + /* Check events */ + if (!check_events(has_vcpu, true, is_pattern, name, errp)) { + return NULL; + } + + /* Get states (all errors checked above) */ ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - TraceEventInfoList *elem = g_new(TraceEventInfoList, 1); + TraceEventInfoList *elem; + bool is_vcpu = trace_event_is_vcpu(ev); + if (has_vcpu && !is_vcpu) { + continue; + } + + elem = g_new(TraceEventInfoList, 1); elem->value = g_new(TraceEventInfo, 1); + elem->value->vcpu = is_vcpu; 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; + if (has_vcpu) { + if (is_vcpu) { + if (trace_event_get_vcpu_state_dynamic(cpu, ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } + /* else: already skipped above */ + } else { + if (trace_event_get_state_dynamic(ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } } elem->next = events; events = elem; - found = true; - } - - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); } return events; } void qmp_trace_event_set_state(const char *name, bool enable, - bool has_ignore_unavailable, - bool ignore_unavailable, Error **errp) + bool has_ignore_unavailable, bool ignore_unavailable, + bool has_vcpu, int64_t vcpu, + Error **errp) { - bool found = false; + Error *err = NULL; TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(name); + CPUState *cpu; - /* 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; - } + /* Check provided vcpu */ + cpu = get_cpu(has_vcpu, vcpu, &err); + if (err) { + error_propagate(errp, err); + return; } - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); + + /* Check events */ + if (!check_events(has_vcpu, has_ignore_unavailable && ignore_unavailable, + is_pattern, name, errp)) { return; } - /* Apply changes */ + /* Apply changes (all errors checked above) */ ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - if (trace_event_get_state_static(ev)) { + if (!trace_event_get_state_static(ev) || + (has_vcpu && !trace_event_is_vcpu(ev))) { + continue; + } + if (has_vcpu) { + trace_event_set_vcpu_state_dynamic(cpu, ev, enable); + } else { trace_event_set_state_dynamic(ev, enable); } } |