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>
This commit is contained in:
Lluís Vilanova 2016-07-11 12:53:57 +02:00 committed by Stefan Hajnoczi
parent bd71211d55
commit 77e2b17272
6 changed files with 206 additions and 46 deletions

View File

@ -646,10 +646,10 @@ ETEXI
{ {
.name = "trace-events", .name = "trace-events",
.args_type = "name:s?", .args_type = "name:s?,vcpu:i?",
.params = "[name]", .params = "[name] [vcpu]",
.help = "show available trace-events & their state " .help = "show available trace-events & their state "
"(name: event name pattern)", "(name: event name pattern; vcpu: vCPU to query, default is any)",
.mhandler.cmd = hmp_info_trace_events, .mhandler.cmd = hmp_info_trace_events,
.command_completion = info_trace_events_completion, .command_completion = info_trace_events_completion,
}, },

View File

@ -281,9 +281,10 @@ ETEXI
{ {
.name = "trace-event", .name = "trace-event",
.args_type = "name:s,option:b", .args_type = "name:s,option:b,vcpu:i?",
.params = "name on|off", .params = "name on|off [vcpu]",
.help = "changes status of a specific trace event", .help = "changes status of a specific trace event "
"(vcpu: vCPU to set, default is all)",
.mhandler.cmd = hmp_trace_event, .mhandler.cmd = hmp_trace_event,
.command_completion = trace_event_completion, .command_completion = trace_event_completion,
}, },

View File

@ -904,9 +904,16 @@ static void hmp_trace_event(Monitor *mon, const QDict *qdict)
{ {
const char *tp_name = qdict_get_str(qdict, "name"); const char *tp_name = qdict_get_str(qdict, "name");
bool new_state = qdict_get_bool(qdict, "option"); bool new_state = qdict_get_bool(qdict, "option");
bool has_vcpu = qdict_haskey(qdict, "vcpu");
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
Error *local_err = NULL; Error *local_err = NULL;
qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err); if (vcpu < 0) {
monitor_printf(mon, "argument vcpu must be positive");
return;
}
qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err);
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);
} }
@ -1066,6 +1073,8 @@ static void hmp_info_cpustats(Monitor *mon, const QDict *qdict)
static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
{ {
const char *name = qdict_get_try_str(qdict, "name"); const char *name = qdict_get_try_str(qdict, "name");
bool has_vcpu = qdict_haskey(qdict, "vcpu");
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
TraceEventInfoList *events; TraceEventInfoList *events;
TraceEventInfoList *elem; TraceEventInfoList *elem;
Error *local_err = NULL; Error *local_err = NULL;
@ -1073,8 +1082,12 @@ static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
if (name == NULL) { if (name == NULL) {
name = "*"; name = "*";
} }
if (vcpu < 0) {
monitor_printf(mon, "argument vcpu must be positive");
return;
}
events = qmp_trace_event_get_state(name, &local_err); events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err);
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);
return; return;

View File

@ -1,6 +1,6 @@
# -*- mode: python -*- # -*- mode: python -*-
# #
# 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. # This work is licensed under the terms of the GNU GPL, version 2 or later.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
@ -29,11 +29,15 @@
# #
# @name: Event name. # @name: Event name.
# @state: Tracing state. # @state: Tracing state.
# @vcpu: Whether this is a per-vCPU event (since 2.7).
#
# An event is per-vCPU if it has the "vcpu" property in the "trace-events"
# files.
# #
# Since 2.2 # Since 2.2
## ##
{ 'struct': 'TraceEventInfo', { 'struct': 'TraceEventInfo',
'data': {'name': 'str', 'state': 'TraceEventState'} } 'data': {'name': 'str', 'state': 'TraceEventState', 'vcpu': 'bool'} }
## ##
# @trace-event-get-state: # @trace-event-get-state:
@ -41,13 +45,23 @@
# Query the state of events. # Query the state of events.
# #
# @name: Event name pattern (case-sensitive glob). # @name: Event name pattern (case-sensitive glob).
# @vcpu: #optional The vCPU to query (any by default; since 2.7).
# #
# Returns: a list of @TraceEventInfo for the matching events # Returns: a list of @TraceEventInfo for the matching events
# #
# An event is returned if:
# - its name matches the @name pattern, and
# - if @vcpu is given, the event has the "vcpu" property.
#
# Therefore, if @vcpu is given, the operation will only match per-vCPU events,
# returning their state on the specified vCPU. Special case: if @name is an
# exact match, @vcpu is given and the event does not have the "vcpu" property,
# an error is returned.
#
# Since 2.2 # Since 2.2
## ##
{ 'command': 'trace-event-get-state', { 'command': 'trace-event-get-state',
'data': {'name': 'str'}, 'data': {'name': 'str', '*vcpu': 'int'},
'returns': ['TraceEventInfo'] } 'returns': ['TraceEventInfo'] }
## ##
@ -58,8 +72,19 @@
# @name: Event name pattern (case-sensitive glob). # @name: Event name pattern (case-sensitive glob).
# @enable: Whether to enable tracing. # @enable: Whether to enable tracing.
# @ignore-unavailable: #optional Do not match unavailable events with @name. # @ignore-unavailable: #optional Do not match unavailable events with @name.
# @vcpu: #optional The vCPU to act upon (all by default; since 2.7).
#
# An event's state is modified if:
# - its name matches the @name pattern, and
# - if @vcpu is given, the event has the "vcpu" property.
#
# Therefore, if @vcpu is given, the operation will only match per-vCPU events,
# setting their state on the specified vCPU. Special case: if @name is an exact
# match, @vcpu is given and the event does not have the "vcpu" property, an
# error is returned.
# #
# Since 2.2 # Since 2.2
## ##
{ 'command': 'trace-event-set-state', { 'command': 'trace-event-set-state',
'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool'} } 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool',
'*vcpu': 'int'} }

View File

@ -4715,7 +4715,7 @@ EQMP
{ {
.name = "trace-event-get-state", .name = "trace-event-get-state",
.args_type = "name:s", .args_type = "name:s,vcpu:i?",
.mhandler.cmd_new = qmp_marshal_trace_event_get_state, .mhandler.cmd_new = qmp_marshal_trace_event_get_state,
}, },
@ -4725,6 +4725,20 @@ trace-event-get-state
Query the state of events. Query the state of events.
Arguments:
- "name": Event name pattern (json-string).
- "vcpu": The vCPU to query, any vCPU by default (json-int, optional).
An event is returned if:
- its name matches the "name" pattern, and
- if "vcpu" is given, the event has the "vcpu" property.
Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
returning their state on the specified vCPU. Special case: if "name" is an exact
match, "vcpu" is given and the event does not have the "vcpu" property, an error
is returned.
Example: Example:
-> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } } -> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } }
@ -4733,7 +4747,7 @@ EQMP
{ {
.name = "trace-event-set-state", .name = "trace-event-set-state",
.args_type = "name:s,enable:b,ignore-unavailable:b?", .args_type = "name:s,enable:b,ignore-unavailable:b?,vcpu:i?",
.mhandler.cmd_new = qmp_marshal_trace_event_set_state, .mhandler.cmd_new = qmp_marshal_trace_event_set_state,
}, },
@ -4743,6 +4757,23 @@ trace-event-set-state
Set the state of events. Set the state of events.
Arguments:
- "name": Event name pattern (json-string).
- "enable": Whether to enable or disable the event (json-bool).
- "ignore-unavailable": Whether to ignore errors for events that cannot be
changed (json-bool, optional).
- "vcpu": The vCPU to act upon, all vCPUs by default (json-int, optional).
An event's state is modified if:
- its name matches the "name" pattern, and
- if "vcpu" is given, the event has the "vcpu" property.
Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
setting their state on the specified vCPU. Special case: if "name" is an exact
match, "vcpu" is given and the event does not have the "vcpu" property, an error
is returned.
Example: Example:
-> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } }

View File

@ -1,7 +1,7 @@
/* /*
* QMP commands for tracing events. * 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. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
@ -12,63 +12,153 @@
#include "trace/control.h" #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)
{ {
TraceEventInfoList *events = NULL; if (has_vcpu) {
bool found = false; CPUState *cpu = qemu_get_cpu(vcpu);
TraceEvent *ev; 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;
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; ev = NULL;
while ((ev = trace_event_pattern(name, 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 = g_new(TraceEventInfo, 1);
elem->value->vcpu = is_vcpu;
elem->value->name = g_strdup(trace_event_get_name(ev)); elem->value->name = g_strdup(trace_event_get_name(ev));
if (!trace_event_get_state_static(ev)) { if (!trace_event_get_state_static(ev)) {
elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE; elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE;
} else if (!trace_event_get_state_dynamic(ev)) {
elem->value->state = TRACE_EVENT_STATE_DISABLED;
} else { } 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; elem->next = events;
events = elem; events = elem;
found = true;
}
if (!found && !trace_event_is_pattern(name)) {
error_setg(errp, "unknown event \"%s\"", name);
} }
return events; return events;
} }
void qmp_trace_event_set_state(const char *name, bool enable, void qmp_trace_event_set_state(const char *name, bool enable,
bool has_ignore_unavailable, bool has_ignore_unavailable, bool ignore_unavailable,
bool ignore_unavailable, Error **errp) bool has_vcpu, int64_t vcpu,
Error **errp)
{ {
bool found = false; Error *err = NULL;
TraceEvent *ev; TraceEvent *ev;
bool is_pattern = trace_event_is_pattern(name);
CPUState *cpu;
/* Check all selected events are dynamic */ /* Check provided vcpu */
ev = NULL; cpu = get_cpu(has_vcpu, vcpu, &err);
while ((ev = trace_event_pattern(name, ev)) != NULL) { if (err) {
found = true; error_propagate(errp, err);
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;
}
}
if (!found && !trace_event_is_pattern(name)) {
error_setg(errp, "unknown event \"%s\"", name);
return; return;
} }
/* Apply changes */ /* Check events */
if (!check_events(has_vcpu, has_ignore_unavailable && ignore_unavailable,
is_pattern, name, errp)) {
return;
}
/* Apply changes (all errors checked above) */
ev = NULL; ev = NULL;
while ((ev = trace_event_pattern(name, 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); trace_event_set_state_dynamic(ev, enable);
} }
} }