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:
parent
bd71211d55
commit
77e2b17272
@ -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,
|
||||||
},
|
},
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
|
17
monitor.c
17
monitor.c
@ -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;
|
||||||
|
@ -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'} }
|
||||||
|
@ -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" } }
|
||||||
|
152
trace/qmp.c
152
trace/qmp.c
@ -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 {
|
||||||
|
if (has_vcpu) {
|
||||||
|
if (is_vcpu) {
|
||||||
|
if (trace_event_get_vcpu_state_dynamic(cpu, ev)) {
|
||||||
elem->value->state = TRACE_EVENT_STATE_ENABLED;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user