-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJXjVFbAAoJEJykq7OBq3PIGZQH/A3FEMEPHgTKXyn11H2nbeMl
 Cc8PQlaZrnKBVEmy3JOP6XItjW4iuKwEgNvwqv8jR48uq4h2zppXsT67vYuVHwMT
 6JrT8X8bAzIJCwfa/jt8WYLIeSeqSFbY9tH5N7trTINs0xQaL9ZuawkOzDkdBxhl
 lFhkFVCH45CW8wXD7Jkicp/GwDiyZVotf3q3LPATN6QhWhiXVAWga1+xGK5rrBJs
 z3m14xCik+LlVkeXtZiqDUnuG0OKlzuGBkb6IMEwz4o7lRyoK1CXl2KgmKFblMpg
 whgE3EKNvE4kPwa2/chq54aQvoBYXEAtwWfUHIOARWIGds9BSsHgNFuePOv19Ds=
 =d0bQ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stefanha/tags/tracing-pull-request' into staging

# gpg: Signature made Mon 18 Jul 2016 22:59:55 BST
# gpg:                using RSA key 0x9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35  775A 9CA4 ABB3 81AB 73C8

* remotes/stefanha/tags/tracing-pull-request:
  trace: Add QAPI/QMP interfaces to query and control per-vCPU tracing state
  trace: Allow event name pattern in "info trace-events"
  trace: Conditionally trace events based on their per-vCPU state
  trace: Add per-vCPU tracing states for events with the 'vcpu' property
  trace: Cosmetic changes on fast-path tracing
  disas: Remove unused macro '_'
  trace: Identify events with the 'vcpu' property
  trace: [bsd-user] Commandline arguments to control tracing
  trace: [linux-user] Commandline arguments to control tracing

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2016-07-19 10:54:49 +01:00
commit 0c1b58f250
37 changed files with 644 additions and 142 deletions

View File

@ -21,6 +21,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu.h" #include "qemu.h"
#include "qemu/config-file.h"
#include "qemu/path.h" #include "qemu/path.h"
#include "qemu/help_option.h" #include "qemu/help_option.h"
/* For tb_lock */ /* For tb_lock */
@ -30,6 +31,8 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/envlist.h" #include "qemu/envlist.h"
#include "exec/log.h" #include "exec/log.h"
#include "trace/control.h"
#include "glib-compat.h"
int singlestep; int singlestep;
unsigned long mmap_min_addr; unsigned long mmap_min_addr;
@ -687,6 +690,8 @@ static void usage(void)
"-p pagesize set the host page size to 'pagesize'\n" "-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n" "-singlestep always run in singlestep mode\n"
"-strace log system calls\n" "-strace log system calls\n"
"-trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
" specify tracing options\n"
"\n" "\n"
"Environment variables:\n" "Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n" "QEMU_STRACE Print system calls and arguments similar to the\n"
@ -735,6 +740,7 @@ int main(int argc, char **argv)
int gdbstub_port = 0; int gdbstub_port = 0;
char **target_environ, **wrk; char **target_environ, **wrk;
envlist_t *envlist = NULL; envlist_t *envlist = NULL;
char *trace_file = NULL;
bsd_type = target_openbsd; bsd_type = target_openbsd;
if (argc <= 1) if (argc <= 1)
@ -754,8 +760,10 @@ int main(int argc, char **argv)
cpu_model = NULL; cpu_model = NULL;
qemu_add_opts(&qemu_trace_opts);
optind = 1; optind = 1;
for(;;) { for (;;) {
if (optind >= argc) if (optind >= argc)
break; break;
r = argv[optind]; r = argv[optind];
@ -840,8 +848,10 @@ int main(int argc, char **argv)
singlestep = 1; singlestep = 1;
} else if (!strcmp(r, "strace")) { } else if (!strcmp(r, "strace")) {
do_strace = 1; do_strace = 1;
} else } else if (!strcmp(r, "trace")) {
{ g_free(trace_file);
trace_file = trace_opt_parse(optarg);
} else {
usage(); usage();
} }
} }
@ -865,6 +875,11 @@ int main(int argc, char **argv)
} }
filename = argv[optind]; filename = argv[optind];
if (!trace_init_backends()) {
exit(1);
}
trace_init_file(trace_file);
/* Zero out regs */ /* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs)); memset(regs, 0, sizeof(struct target_pt_regs));
@ -1116,6 +1131,7 @@ int main(int argc, char **argv)
gdbserver_start (gdbstub_port); gdbserver_start (gdbstub_port);
gdb_handlesig(cpu, 0); gdb_handlesig(cpu, 0);
} }
trace_init_vcpu_events();
cpu_loop(env); cpu_loop(env);
/* never exits */ /* never exits */
return 0; return 0;

View File

@ -521,7 +521,7 @@ static unsigned
insert_bdisp(unsigned insn, int value, const char **errmsg) insert_bdisp(unsigned insn, int value, const char **errmsg)
{ {
if (errmsg != (const char **)NULL && (value & 3)) if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("branch operand unaligned"); *errmsg = "branch operand unaligned";
return insn | ((value / 4) & 0x1FFFFF); return insn | ((value / 4) & 0x1FFFFF);
} }
@ -539,7 +539,7 @@ static unsigned
insert_jhint(unsigned insn, int value, const char **errmsg) insert_jhint(unsigned insn, int value, const char **errmsg)
{ {
if (errmsg != (const char **)NULL && (value & 3)) if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("jump hint unaligned"); *errmsg = "jump hint unaligned";
return insn | ((value / 4) & 0x3FFF); return insn | ((value / 4) & 0x3FFF);
} }
@ -556,7 +556,7 @@ static unsigned
insert_ev6hwjhint(unsigned insn, int value, const char **errmsg) insert_ev6hwjhint(unsigned insn, int value, const char **errmsg)
{ {
if (errmsg != (const char **)NULL && (value & 3)) if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("jump hint unaligned"); *errmsg = "jump hint unaligned";
return insn | ((value / 4) & 0x1FFF); return insn | ((value / 4) & 0x1FFF);
} }

View File

@ -1817,7 +1817,7 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given,
func (stream, "e"); func (stream, "e");
break; break;
default: default:
func (stream, _("<illegal precision>")); func (stream, "<illegal precision>");
break; break;
} }
break; break;

View File

@ -3406,7 +3406,7 @@ static const struct dis386 three_byte_table[][256] = {
} }
}; };
#define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>") #define INTERNAL_DISASSEMBLER_ERROR "<internal disassembler error>"
static void static void
ckprefix (void) ckprefix (void)

View File

@ -1676,7 +1676,7 @@ print_insn_arg (const char *d,
(*info->fprintf_func) (info->stream, "%%sfc"); (*info->fprintf_func) (info->stream, "%%sfc");
else else
/* xgettext:c-format */ /* xgettext:c-format */
(*info->fprintf_func) (info->stream, _("<function code %d>"), fc); (*info->fprintf_func) (info->stream, "<function code %d>", fc);
} }
break; break;
@ -1827,7 +1827,7 @@ match_insn_m68k (bfd_vma memaddr,
{ {
info->fprintf_func (info->stream, info->fprintf_func (info->stream,
/* xgettext:c-format */ /* xgettext:c-format */
_("<internal error in opcode table: %s %s>\n"), "<internal error in opcode table: %s %s>\n",
best->name, best->args); best->name, best->args);
info->fprintf_func = save_printer; info->fprintf_func = save_printer;
info->print_address_func = save_print_address; info->print_address_func = save_print_address;

View File

@ -4257,7 +4257,7 @@ print_insn_args (const char *d,
case '\0': case '\0':
/* xgettext:c-format */ /* xgettext:c-format */
(*info->fprintf_func) (info->stream, (*info->fprintf_func) (info->stream,
_("# internal error, incomplete extension sequence (+)")); "# internal error, incomplete extension sequence (+)");
return; return;
case 'A': case 'A':
@ -4515,7 +4515,7 @@ print_insn_args (const char *d,
default: default:
/* xgettext:c-format */ /* xgettext:c-format */
(*info->fprintf_func) (info->stream, (*info->fprintf_func) (info->stream,
_("# internal error, undefined extension sequence (+%c)"), "# internal error, undefined extension sequence (+%c)",
*d); *d);
return; return;
} }
@ -4875,7 +4875,7 @@ print_insn_args (const char *d,
default: default:
/* xgettext:c-format */ /* xgettext:c-format */
(*info->fprintf_func) (info->stream, (*info->fprintf_func) (info->stream,
_("# internal error, undefined modifier(%c)"), "# internal error, undefined modifier(%c)",
*d); *d);
return; return;
} }
@ -5739,7 +5739,7 @@ print_mips16_insn_arg (char type,
/* xgettext:c-format */ /* xgettext:c-format */
(*info->fprintf_func) (*info->fprintf_func)
(info->stream, (info->stream,
_("# internal disassembler error, unrecognised modifier (%c)"), "# internal disassembler error, unrecognised modifier (%c)",
type); type);
abort (); abort ();
} }
@ -5750,51 +5750,51 @@ print_mips_disassembler_options (FILE *stream)
{ {
unsigned int i; unsigned int i;
fprintf (stream, _("\n\ fprintf (stream, "\n\
The following MIPS specific disassembler options are supported for use\n\ The following MIPS specific disassembler options are supported for use\n\
with the -M switch (multiple options should be separated by commas):\n")); with the -M switch (multiple options should be separated by commas):\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
gpr-names=ABI Print GPR names according to specified ABI.\n\ gpr-names=ABI Print GPR names according to specified ABI.\n\
Default: based on binary being disassembled.\n")); Default: based on binary being disassembled.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
fpr-names=ABI Print FPR names according to specified ABI.\n\ fpr-names=ABI Print FPR names according to specified ABI.\n\
Default: numeric.\n")); Default: numeric.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
cp0-names=ARCH Print CP0 register names according to\n\ cp0-names=ARCH Print CP0 register names according to\n\
specified architecture.\n\ specified architecture.\n\
Default: based on binary being disassembled.\n")); Default: based on binary being disassembled.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
hwr-names=ARCH Print HWR names according to specified\n\ hwr-names=ARCH Print HWR names according to specified\n\
architecture.\n\ architecture.\n\
Default: based on binary being disassembled.\n")); Default: based on binary being disassembled.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
reg-names=ABI Print GPR and FPR names according to\n\ reg-names=ABI Print GPR and FPR names according to\n\
specified ABI.\n")); specified ABI.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
reg-names=ARCH Print CP0 register and HWR names according to\n\ reg-names=ARCH Print CP0 register and HWR names according to\n\
specified architecture.\n")); specified architecture.\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
For the options above, the following values are supported for \"ABI\":\n\ For the options above, the following values are supported for \"ABI\":\n\
")); ");
for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
fprintf (stream, " %s", mips_abi_choices[i].name); fprintf (stream, " %s", mips_abi_choices[i].name);
fprintf (stream, _("\n")); fprintf (stream, "\n");
fprintf (stream, _("\n\ fprintf (stream, "\n\
For the options above, The following values are supported for \"ARCH\":\n\ For the options above, The following values are supported for \"ARCH\":\n\
")); ");
for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
if (*mips_arch_choices[i].name != '\0') if (*mips_arch_choices[i].name != '\0')
fprintf (stream, " %s", mips_arch_choices[i].name); fprintf (stream, " %s", mips_arch_choices[i].name);
fprintf (stream, _("\n")); fprintf (stream, "\n");
fprintf (stream, _("\n")); fprintf (stream, "\n");
} }
#endif #endif

View File

@ -1120,7 +1120,7 @@ insert_bo (unsigned long insn,
const char **errmsg) const char **errmsg)
{ {
if (!valid_bo (value, dialect, 0)) if (!valid_bo (value, dialect, 0))
*errmsg = _("invalid conditional option"); *errmsg = "invalid conditional option";
return insn | ((value & 0x1f) << 21); return insn | ((value & 0x1f) << 21);
} }
@ -1148,9 +1148,9 @@ insert_boe (unsigned long insn,
const char **errmsg) const char **errmsg)
{ {
if (!valid_bo (value, dialect, 0)) if (!valid_bo (value, dialect, 0))
*errmsg = _("invalid conditional option"); *errmsg = "invalid conditional option";
else if ((value & 1) != 0) else if ((value & 1) != 0)
*errmsg = _("attempt to set y bit when using + or - modifier"); *errmsg = "attempt to set y bit when using + or - modifier";
return insn | ((value & 0x1f) << 21); return insn | ((value & 0x1f) << 21);
} }
@ -1182,7 +1182,7 @@ insert_fxm (unsigned long insn,
{ {
if (value == 0 || (value & -value) != value) if (value == 0 || (value & -value) != value)
{ {
*errmsg = _("invalid mask field"); *errmsg = "invalid mask field";
value = 0; value = 0;
} }
} }
@ -1208,7 +1208,7 @@ insert_fxm (unsigned long insn,
/* Any other value on mfcr is an error. */ /* Any other value on mfcr is an error. */
else if ((insn & (0x3ff << 1)) == 19 << 1) else if ((insn & (0x3ff << 1)) == 19 << 1)
{ {
*errmsg = _("ignoring invalid mfcr mask"); *errmsg = "ignoring invalid mfcr mask";
value = 0; value = 0;
} }
@ -1258,7 +1258,7 @@ insert_mbe (unsigned long insn,
if (uval == 0) if (uval == 0)
{ {
*errmsg = _("illegal bitmask"); *errmsg = "illegal bitmask";
return insn; return insn;
} }
@ -1293,7 +1293,7 @@ insert_mbe (unsigned long insn,
me = 32; me = 32;
if (count != 2 && (count != 0 || ! last)) if (count != 2 && (count != 0 || ! last))
*errmsg = _("illegal bitmask"); *errmsg = "illegal bitmask";
return insn | (mb << 6) | ((me - 1) << 1); return insn | (mb << 6) | ((me - 1) << 1);
} }
@ -1413,7 +1413,7 @@ insert_ram (unsigned long insn,
const char **errmsg) const char **errmsg)
{ {
if ((unsigned long) value >= ((insn >> 21) & 0x1f)) if ((unsigned long) value >= ((insn >> 21) & 0x1f))
*errmsg = _("index register in load range"); *errmsg = "index register in load range";
return insn | ((value & 0x1f) << 16); return insn | ((value & 0x1f) << 16);
} }
@ -1429,7 +1429,7 @@ insert_raq (unsigned long insn,
long rtvalue = (insn & RT_MASK) >> 21; long rtvalue = (insn & RT_MASK) >> 21;
if (value == rtvalue) if (value == rtvalue)
*errmsg = _("source and target register operands must be different"); *errmsg = "source and target register operands must be different";
return insn | ((value & 0x1f) << 16); return insn | ((value & 0x1f) << 16);
} }
@ -1444,7 +1444,7 @@ insert_ras (unsigned long insn,
const char **errmsg) const char **errmsg)
{ {
if (value == 0) if (value == 0)
*errmsg = _("invalid register operand when updating"); *errmsg = "invalid register operand when updating";
return insn | ((value & 0x1f) << 16); return insn | ((value & 0x1f) << 16);
} }
@ -1526,7 +1526,7 @@ insert_sprg (unsigned long insn,
if (value > 7 if (value > 7
|| (value > 3 || (value > 3
&& (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0)) && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0))
*errmsg = _("invalid sprg number"); *errmsg = "invalid sprg number";
/* If this is mfsprg4..7 then use spr 260..263 which can be read in /* If this is mfsprg4..7 then use spr 260..263 which can be read in
user mode. Anything else must use spr 272..279. */ user mode. Anything else must use spr 272..279. */

View File

@ -2494,7 +2494,7 @@ compare_opcodes (const void * a, const void * b)
fprintf fprintf
(stderr, (stderr,
/* xgettext:c-format */ /* xgettext:c-format */
_("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op0->name, match0, lose0); op0->name, match0, lose0);
op0->lose &= ~op0->match; op0->lose &= ~op0->match;
lose0 = op0->lose; lose0 = op0->lose;
@ -2505,7 +2505,7 @@ compare_opcodes (const void * a, const void * b)
fprintf fprintf
(stderr, (stderr,
/* xgettext:c-format */ /* xgettext:c-format */
_("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op1->name, match1, lose1); op1->name, match1, lose1);
op1->lose &= ~op1->match; op1->lose &= ~op1->match;
lose1 = op1->lose; lose1 = op1->lose;
@ -2555,7 +2555,7 @@ compare_opcodes (const void * a, const void * b)
else else
fprintf (stderr, fprintf (stderr,
/* xgettext:c-format */ /* xgettext:c-format */
_("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n",
op0->name, op1->name); op0->name, op1->name);
} }

View File

@ -646,10 +646,12 @@ ETEXI
{ {
.name = "trace-events", .name = "trace-events",
.args_type = "", .args_type = "name:s?,vcpu:i?",
.params = "", .params = "[name] [vcpu]",
.help = "show available trace-events & their state", .help = "show available trace-events & their state "
"(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,
}, },
STEXI STEXI

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,
}, },

1
hmp.h
View File

@ -115,6 +115,7 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str); void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str); void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str); void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str);
void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str);
void trace_event_completion(ReadLineState *rs, int nb_args, const char *str); void trace_event_completion(ReadLineState *rs, int nb_args, const char *str);
void watchdog_action_completion(ReadLineState *rs, int nb_args, void watchdog_action_completion(ReadLineState *rs, int nb_args,
const char *str); const char *str);

View File

@ -477,7 +477,6 @@ int generic_symbol_at_address(bfd_vma, struct disassemble_info *);
(INFO).disassembler_options = NULL, \ (INFO).disassembler_options = NULL, \
(INFO).insn_info_valid = 0 (INFO).insn_info_valid = 0
#define _(x) x
#define ATTRIBUTE_UNUSED __attribute__((unused)) #define ATTRIBUTE_UNUSED __attribute__((unused))
/* from libbfd */ /* from libbfd */

View File

@ -24,8 +24,10 @@
#include "disas/bfd.h" #include "disas/bfd.h"
#include "exec/hwaddr.h" #include "exec/hwaddr.h"
#include "exec/memattrs.h" #include "exec/memattrs.h"
#include "qemu/bitmap.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu/thread.h" #include "qemu/thread.h"
#include "trace/generated-events.h"
typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
void *opaque); void *opaque);
@ -280,6 +282,7 @@ struct qemu_work_item {
* @kvm_fd: vCPU file descriptor for KVM. * @kvm_fd: vCPU file descriptor for KVM.
* @work_mutex: Lock to prevent multiple access to queued_work_*. * @work_mutex: Lock to prevent multiple access to queued_work_*.
* @queued_work_first: First asynchronous work pending. * @queued_work_first: First asynchronous work pending.
* @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).
* *
* State of one CPU core or thread. * State of one CPU core or thread.
*/ */
@ -347,6 +350,9 @@ struct CPUState {
struct KVMState *kvm_state; struct KVMState *kvm_state;
struct kvm_run *kvm_run; struct kvm_run *kvm_run;
/* Used for events with 'vcpu' and *without* the 'disabled' properties */
DECLARE_BITMAP(trace_dstate, TRACE_VCPU_EVENT_COUNT);
/* TODO Move common fields from CPUArchState here. */ /* TODO Move common fields from CPUArchState here. */
int cpu_index; /* used by alpha TCG */ int cpu_index; /* used by alpha TCG */
uint32_t halted; /* used by alpha, cris, ppc TCG */ uint32_t halted; /* used by alpha, cris, ppc TCG */

View File

@ -24,6 +24,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu.h" #include "qemu.h"
#include "qemu/path.h" #include "qemu/path.h"
#include "qemu/config-file.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/help_option.h" #include "qemu/help_option.h"
#include "cpu.h" #include "cpu.h"
@ -33,6 +34,8 @@
#include "qemu/envlist.h" #include "qemu/envlist.h"
#include "elf.h" #include "elf.h"
#include "exec/log.h" #include "exec/log.h"
#include "trace/control.h"
#include "glib-compat.h"
char *exec_path; char *exec_path;
@ -4001,6 +4004,13 @@ static void handle_arg_version(const char *arg)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static char *trace_file;
static void handle_arg_trace(const char *arg)
{
g_free(trace_file);
trace_file = trace_opt_parse(arg);
}
struct qemu_argument { struct qemu_argument {
const char *argv; const char *argv;
const char *env; const char *env;
@ -4048,6 +4058,8 @@ static const struct qemu_argument arg_table[] = {
"", "log system calls"}, "", "log system calls"},
{"seed", "QEMU_RAND_SEED", true, handle_arg_randseed, {"seed", "QEMU_RAND_SEED", true, handle_arg_randseed,
"", "Seed for pseudo-random number generator"}, "", "Seed for pseudo-random number generator"},
{"trace", "QEMU_TRACE", true, handle_arg_trace,
"", "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
{"version", "QEMU_VERSION", false, handle_arg_version, {"version", "QEMU_VERSION", false, handle_arg_version,
"", "display version information and exit"}, "", "display version information and exit"},
{NULL, NULL, false, NULL, NULL, NULL} {NULL, NULL, false, NULL, NULL, NULL}
@ -4237,8 +4249,15 @@ int main(int argc, char **argv, char **envp)
srand(time(NULL)); srand(time(NULL));
qemu_add_opts(&qemu_trace_opts);
optind = parse_args(argc, argv); optind = parse_args(argc, argv);
if (!trace_init_backends()) {
exit(1);
}
trace_init_file(trace_file);
/* Zero out regs */ /* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs)); memset(regs, 0, sizeof(struct target_pt_regs));
@ -4791,6 +4810,7 @@ int main(int argc, char **argv, char **envp)
} }
gdb_handlesig(cpu, 0); gdb_handlesig(cpu, 0);
} }
trace_init_vcpu_events();
cpu_loop(env); cpu_loop(env);
/* never exits */ /* never exits */
return 0; return 0;

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);
} }
@ -1065,8 +1072,26 @@ 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)
{ {
TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL); 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 *elem; TraceEventInfoList *elem;
Error *local_err = NULL;
if (name == NULL) {
name = "*";
}
if (vcpu < 0) {
monitor_printf(mon, "argument vcpu must be positive");
return;
}
events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err);
if (local_err) {
error_report_err(local_err);
return;
}
for (elem = events; elem != NULL; elem = elem->next) { for (elem = events; elem != NULL; elem = elem->next) {
monitor_printf(mon, "%s : state %u\n", monitor_printf(mon, "%s : state %u\n",
@ -3296,6 +3321,23 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
} }
} }
void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
TraceEventID id;
for (id = 0; id < trace_event_count(); id++) {
const char *event_name = trace_event_get_name(trace_event_id(id));
if (!strncmp(str, event_name, len)) {
readline_add_completion(rs, event_name);
}
}
}
}
void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) void trace_event_completion(ReadLineState *rs, int nb_args, const char *str)
{ {
size_t len; size_t len;

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

@ -345,6 +345,7 @@ static void cpu_common_initfn(Object *obj)
qemu_mutex_init(&cpu->work_mutex); qemu_mutex_init(&cpu->work_mutex);
QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->breakpoints);
QTAILQ_INIT(&cpu->watchpoints); QTAILQ_INIT(&cpu->watchpoints);
bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT);
} }
static void cpu_common_finalize(Object *obj) static void cpu_common_finalize(Object *obj)

View File

@ -6,7 +6,7 @@ DTrace/SystemTAP backend.
""" """
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" __author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" __copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version" __license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi" __maintainer__ = "Stefan Hajnoczi"

View File

@ -6,7 +6,7 @@ Stderr built-in backend.
""" """
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" __author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" __copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version" __license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi" __maintainer__ = "Stefan Hajnoczi"
@ -30,7 +30,13 @@ def generate_h(event):
if len(event.args) > 0: if len(event.args) > 0:
argnames = ", " + argnames argnames = ", " + argnames
out(' if (trace_event_get_state(%(event_id)s)) {', if "vcpu" in event.properties:
# already checked on the generic format code
cond = "true"
else:
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
out(' if (%(cond)s) {',
' struct timeval _now;', ' struct timeval _now;',
' gettimeofday(&_now, NULL);', ' gettimeofday(&_now, NULL);',
' qemu_log_mask(LOG_TRACE, "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",', ' qemu_log_mask(LOG_TRACE, "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",',
@ -38,7 +44,7 @@ def generate_h(event):
' (size_t)_now.tv_sec, (size_t)_now.tv_usec', ' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
' %(argnames)s);', ' %(argnames)s);',
' }', ' }',
event_id="TRACE_" + event.name.upper(), cond=cond,
name=event.name, name=event.name,
fmt=event.fmt.rstrip("\n"), fmt=event.fmt.rstrip("\n"),
argnames=argnames) argnames=argnames)

View File

@ -68,16 +68,23 @@ def generate_c(event):
if len(event.args) == 0: if len(event.args) == 0:
sizestr = '0' sizestr = '0'
event_id = 'TRACE_' + event.name.upper()
if "vcpu" in event.properties:
# already checked on the generic format code
cond = "true"
else:
cond = "trace_event_get_state(%s)" % event_id
out('', out('',
' if (!trace_event_get_state(%(event_id)s)) {', ' if (!%(cond)s) {',
' return;', ' return;',
' }', ' }',
'', '',
' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {',
' return; /* Trace Buffer Full, Event Dropped ! */', ' return; /* Trace Buffer Full, Event Dropped ! */',
' }', ' }',
event_id='TRACE_' + event.name.upper(), cond=cond,
event_id=event_id,
size_str=sizestr) size_str=sizestr)
if len(event.args) > 0: if len(event.args) > 0:

View File

@ -6,7 +6,7 @@ LTTng User Space Tracing backend.
""" """
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" __author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" __copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version" __license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi" __maintainer__ = "Stefan Hajnoczi"

View File

@ -6,7 +6,7 @@ trace/generated-events.c
""" """
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" __author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" __copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version" __license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi" __maintainer__ = "Stefan Hajnoczi"
@ -28,8 +28,15 @@ def generate(events, backend):
out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {')
for e in events: for e in events:
out(' { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s },', if "vcpu" in e.properties:
vcpu_id = "TRACE_VCPU_" + e.name.upper()
else:
vcpu_id = "TRACE_VCPU_EVENT_COUNT"
out(' { .id = %(id)s, .vcpu_id = %(vcpu_id)s,'
' .name = \"%(name)s\",'
' .sstate = %(sstate)s },',
id = "TRACE_" + e.name.upper(), id = "TRACE_" + e.name.upper(),
vcpu_id = vcpu_id,
name = e.name, name = e.name,
sstate = "TRACE_%s_ENABLED" % e.name.upper()) sstate = "TRACE_%s_ENABLED" % e.name.upper())

View File

@ -32,13 +32,23 @@ def generate(events, backend):
out(' TRACE_EVENT_COUNT', out(' TRACE_EVENT_COUNT',
'} TraceEventID;') '} TraceEventID;')
# per-vCPU event identifiers
out('typedef enum {')
for e in events:
if "vcpu" in e.properties:
out(' TRACE_VCPU_%s,' % e.name.upper())
out(' TRACE_VCPU_EVENT_COUNT',
'} TraceEventVCPUID;')
# static state # static state
for e in events: for e in events:
if 'disable' in e.properties: if 'disable' in e.properties:
enabled = 0 enabled = 0
else: else:
enabled = 1 enabled = 1
if "tcg-trans" in e.properties: if "tcg-exec" in e.properties:
# a single define for the two "sub-events" # a single define for the two "sub-events"
out('#define TRACE_%(name)s_ENABLED %(enabled)d', out('#define TRACE_%(name)s_ENABLED %(enabled)d',
name=e.original.name.upper(), name=e.original.name.upper(),

View File

@ -23,21 +23,36 @@ def generate(events, backend):
'#define TRACE__GENERATED_TRACERS_H', '#define TRACE__GENERATED_TRACERS_H',
'', '',
'#include "qemu-common.h"', '#include "qemu-common.h"',
'#include "trace/control.h"',
'') '')
backend.generate_begin(events) backend.generate_begin(events)
for e in events: for e in events:
if "vcpu" in e.properties:
trace_cpu = next(iter(e.args))[1]
cond = "trace_event_get_vcpu_state(%(cpu)s,"\
" TRACE_%(id)s,"\
" TRACE_VCPU_%(id)s)"\
% dict(
cpu=trace_cpu,
id=e.name.upper())
else:
cond = "true"
out('', out('',
'static inline void %(api)s(%(args)s)', 'static inline void %(api)s(%(args)s)',
'{', '{',
' if (%(cond)s) {',
api=e.api(), api=e.api(),
args=e.args) args=e.args,
cond=cond)
if "disable" not in e.properties: if "disable" not in e.properties:
backend.generate(e) backend.generate(e)
out('}') out(' }',
'}')
backend.generate_end(events) backend.generate_end(events)

View File

@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o stub-obj-y += slirp.o
stub-obj-y += sysbus.o stub-obj-y += sysbus.o
stub-obj-y += trace-control.o
stub-obj-y += uuid.o stub-obj-y += uuid.o
stub-obj-y += vm-stop.o stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o stub-obj-y += vmstate.o

28
stubs/trace-control.c Normal file
View File

@ -0,0 +1,28 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
* 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.
*/
#include "qemu/osdep.h"
#include "trace/control.h"
void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
TraceEventID id;
assert(trace_event_get_state_static(ev));
id = trace_event_get_id(ev);
trace_events_enabled_count += state - trace_events_dstate[id];
trace_events_dstate[id] = state;
}
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state)
{
/* should never be called on non-target binaries */
abort();
}

View File

@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%)
# Auto-generated event descriptions for LTTng ust code # Auto-generated event descriptions for LTTng ust code
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
$(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp $(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@ @cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
@ -33,6 +34,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
$(obj)/generated-events.h: $(obj)/generated-ust-provider.h $(obj)/generated-events.h: $(obj)/generated-ust-provider.h
$(obj)/generated-events.c: $(obj)/generated-ust.c $(obj)/generated-events.c: $(obj)/generated-ust.c
endif endif
###################################################################### ######################################################################
@ -91,6 +93,7 @@ $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.
# but that gets picked up by QEMU's Makefile as an external dependency # but that gets picked up by QEMU's Makefile as an external dependency
# rule file. So we use '.dtrace' instead # rule file. So we use '.dtrace' instead
ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace)
$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp $(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp
@cmp $< $@ >/dev/null 2>&1 || cp $< $@ @cmp $< $@ >/dev/null 2>&1 || cp $< $@
$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y) $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR)/config-host.mak $(tracetool-y)
@ -155,4 +158,5 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o
util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o
util-obj-$(CONFIG_TRACE_UST) += generated-ust.o util-obj-$(CONFIG_TRACE_UST) += generated-ust.o
util-obj-y += control.o util-obj-y += control.o
target-obj-y += control-target.o
util-obj-y += qmp.o util-obj-y += qmp.o

View File

@ -1,7 +1,7 @@
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* 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.
@ -10,8 +10,13 @@
#ifndef TRACE__CONTROL_INTERNAL_H #ifndef TRACE__CONTROL_INTERNAL_H
#define TRACE__CONTROL_INTERNAL_H #define TRACE__CONTROL_INTERNAL_H
#include <stddef.h> /* size_t */
#include "qom/cpu.h"
extern TraceEvent trace_events[]; extern TraceEvent trace_events[];
extern bool trace_events_dstate[]; extern uint16_t trace_events_dstate[];
extern int trace_events_enabled_count; extern int trace_events_enabled_count;
@ -38,6 +43,16 @@ static inline TraceEventID trace_event_get_id(TraceEvent *ev)
return ev->id; return ev->id;
} }
static inline TraceEventVCPUID trace_event_get_vcpu_id(TraceEvent *ev)
{
return ev->vcpu_id;
}
static inline bool trace_event_is_vcpu(TraceEvent *ev)
{
return ev->vcpu_id != TRACE_VCPU_EVENT_COUNT;
}
static inline const char * trace_event_get_name(TraceEvent *ev) static inline const char * trace_event_get_name(TraceEvent *ev)
{ {
assert(ev != NULL); assert(ev != NULL);
@ -50,24 +65,38 @@ static inline bool trace_event_get_state_static(TraceEvent *ev)
return ev->sstate; return ev->sstate;
} }
static inline bool trace_event_get_state_dynamic_by_id(int id) static inline bool trace_event_get_state_dynamic_by_id(TraceEventID id)
{ {
/* it's on fast path, avoid consistency checks (asserts) */
return unlikely(trace_events_enabled_count) && trace_events_dstate[id]; return unlikely(trace_events_enabled_count) && trace_events_dstate[id];
} }
static inline bool trace_event_get_state_dynamic(TraceEvent *ev) static inline bool trace_event_get_state_dynamic(TraceEvent *ev)
{ {
int id = trace_event_get_id(ev); TraceEventID id;
assert(trace_event_get_state_static(ev));
id = trace_event_get_id(ev);
return trace_event_get_state_dynamic_by_id(id); return trace_event_get_state_dynamic_by_id(id);
} }
static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu,
TraceEventVCPUID id)
{ {
int id = trace_event_get_id(ev); /* it's on fast path, avoid consistency checks (asserts) */
assert(ev != NULL); if (unlikely(trace_events_enabled_count)) {
assert(trace_event_get_state_static(ev)); return test_bit(id, vcpu->trace_dstate);
trace_events_enabled_count += state - trace_events_dstate[id]; } else {
trace_events_dstate[id] = state; return false;
}
}
static inline bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev)
{
TraceEventVCPUID id;
assert(trace_event_is_vcpu(ev));
id = trace_event_get_vcpu_id(ev);
return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, id);
} }
#endif /* TRACE__CONTROL_INTERNAL_H */ #endif /* TRACE__CONTROL_INTERNAL_H */

53
trace/control-target.c Normal file
View File

@ -0,0 +1,53 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
* 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.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "trace/control.h"
#include "translate-all.h"
void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
CPUState *vcpu;
assert(trace_event_get_state_static(ev));
if (trace_event_is_vcpu(ev)) {
CPU_FOREACH(vcpu) {
trace_event_set_vcpu_state_dynamic(vcpu, ev, state);
}
} else {
TraceEventID id = trace_event_get_id(ev);
trace_events_enabled_count += state - trace_events_dstate[id];
trace_events_dstate[id] = state;
}
}
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state)
{
TraceEventID id;
TraceEventVCPUID vcpu_id;
bool state_pre;
assert(trace_event_get_state_static(ev));
assert(trace_event_is_vcpu(ev));
id = trace_event_get_id(ev);
vcpu_id = trace_event_get_vcpu_id(ev);
state_pre = test_bit(vcpu_id, vcpu->trace_dstate);
if (state_pre != state) {
if (state) {
trace_events_enabled_count++;
set_bit(vcpu_id, vcpu->trace_dstate);
trace_events_dstate[id]++;
} else {
trace_events_enabled_count--;
clear_bit(vcpu_id, vcpu->trace_dstate);
trace_events_dstate[id]--;
}
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* 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.
@ -25,7 +25,14 @@
#include "monitor/monitor.h" #include "monitor/monitor.h"
int trace_events_enabled_count; int trace_events_enabled_count;
bool trace_events_dstate[TRACE_EVENT_COUNT]; /*
* Interpretation depends on wether the event has the 'vcpu' property:
* - false: Boolean value indicating whether the event is active.
* - true : Integral counting the number of vCPUs that have this event enabled.
*/
uint16_t trace_events_dstate[TRACE_EVENT_COUNT];
/* Marks events for late vCPU state init */
static bool trace_events_dstate_init[TRACE_EVENT_COUNT];
QemuOptsList qemu_trace_opts = { QemuOptsList qemu_trace_opts = {
.name = "trace", .name = "trace",
@ -135,7 +142,10 @@ static void do_trace_enable_events(const char *line_buf)
TraceEvent *ev = NULL; TraceEvent *ev = NULL;
while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
if (trace_event_get_state_static(ev)) { if (trace_event_get_state_static(ev)) {
/* start tracing */
trace_event_set_state_dynamic(ev, enable); trace_event_set_state_dynamic(ev, enable);
/* mark for late vCPU init */
trace_events_dstate_init[ev->id] = true;
} }
} }
} else { } else {
@ -147,7 +157,10 @@ static void do_trace_enable_events(const char *line_buf)
error_report("WARNING: trace event '%s' is not traceable", error_report("WARNING: trace event '%s' is not traceable",
line_ptr); line_ptr);
} else { } else {
/* start tracing */
trace_event_set_state_dynamic(ev, enable); trace_event_set_state_dynamic(ev, enable);
/* mark for late vCPU init */
trace_events_dstate_init[ev->id] = true;
} }
} }
} }
@ -257,3 +270,15 @@ char *trace_opt_parse(const char *optarg)
return trace_file; return trace_file;
} }
void trace_init_vcpu_events(void)
{
TraceEvent *ev = NULL;
while ((ev = trace_event_pattern("*", ev)) != NULL) {
if (trace_event_is_vcpu(ev) &&
trace_event_get_state_static(ev) &&
trace_events_dstate_init[ev->id]) {
trace_event_set_state_dynamic(ev, true);
}
}
}

View File

@ -85,6 +85,23 @@ static TraceEventID trace_event_count(void);
*/ */
static TraceEventID trace_event_get_id(TraceEvent *ev); static TraceEventID trace_event_get_id(TraceEvent *ev);
/**
* trace_event_get_vcpu_id:
*
* Get the per-vCPU identifier of an event.
*
* Special value #TRACE_VCPU_EVENT_COUNT means the event is not vCPU-specific
* (does not have the "vcpu" property).
*/
static TraceEventVCPUID trace_event_get_vcpu_id(TraceEvent *ev);
/**
* trace_event_is_vcpu:
*
* Whether this is a per-vCPU event.
*/
static bool trace_event_is_vcpu(TraceEvent *ev);
/** /**
* trace_event_get_name: * trace_event_get_name:
* *
@ -106,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev);
#define trace_event_get_state(id) \ #define trace_event_get_state(id) \
((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id)) ((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id))
/**
* trace_event_get_vcpu_state:
* @vcpu: Target vCPU.
* @id: Event identifier (TraceEventID).
* @vcpu_id: Per-vCPU event identifier (TraceEventVCPUID).
*
* 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_vcpu_state(vcpu, id, vcpu_id) \
((id ##_ENABLED) && trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id))
/** /**
* trace_event_get_state_static: * trace_event_get_state_static:
* @id: Event identifier. * @id: Event identifier.
@ -121,9 +155,18 @@ static bool trace_event_get_state_static(TraceEvent *ev);
* trace_event_get_state_dynamic: * trace_event_get_state_dynamic:
* *
* Get the dynamic tracing state of an event. * Get the dynamic tracing state of an event.
*
* If the event has the 'vcpu' property, gets the OR'ed state of all vCPUs.
*/ */
static bool trace_event_get_state_dynamic(TraceEvent *ev); static bool trace_event_get_state_dynamic(TraceEvent *ev);
/**
* trace_event_get_vcpu_state_dynamic:
*
* Get the dynamic tracing state of an event for the given vCPU.
*/
static bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev);
/** /**
* trace_event_set_state: * trace_event_set_state:
* *
@ -137,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev);
} \ } \
} while (0) } while (0)
/**
* trace_event_set_vcpu_state:
*
* Set the tracing state of an event for the given vCPU (only if not disabled).
*/
#define trace_event_set_vcpu_state(vcpu, id, state) \
do { \
if ((id ##_ENABLED)) { \
TraceEvent *_e = trace_event_id(id); \
trace_event_set_vcpu_state_dynamic(vcpu, _e, state); \
} \
} while (0)
/** /**
* trace_event_set_state_dynamic: * trace_event_set_state_dynamic:
* *
* Set the dynamic tracing state of an event. * Set the dynamic tracing state of an event.
* *
* If the event has the 'vcpu' property, sets the state on all vCPUs.
*
* Pre-condition: trace_event_get_state_static(ev) == true * 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_vcpu_state_dynamic:
*
* Set the dynamic tracing state of an event for the given vCPU.
*
* Pre-condition: trace_event_get_vcpu_state_static(ev) == true
*/
void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
TraceEvent *ev, bool state);
@ -201,6 +269,15 @@ extern QemuOptsList qemu_trace_opts;
*/ */
char *trace_opt_parse(const char *optarg); char *trace_opt_parse(const char *optarg);
/**
* trace_init_vcpu_events:
*
* Re-synchronize initial event state with vCPUs (which can be created after
* trace_init_events()).
*/
void trace_init_vcpu_events(void);
#include "trace/control-internal.h" #include "trace/control-internal.h"
#endif /* TRACE__CONTROL_H */ #endif /* TRACE__CONTROL_H */

View File

@ -1,7 +1,7 @@
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* Copyright (C) 2012 Lluís Vilanova <vilanova@ac.upc.edu> * Copyright (C) 2012-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.
@ -16,6 +16,7 @@
/** /**
* TraceEvent: * TraceEvent:
* @id: Unique event identifier. * @id: Unique event identifier.
* @vcpu_id: Unique per-vCPU event identifier.
* @name: Event name. * @name: Event name.
* @sstate: Static tracing state. * @sstate: Static tracing state.
* *
@ -23,6 +24,7 @@
*/ */
typedef struct TraceEvent { typedef struct TraceEvent {
TraceEventID id; TraceEventID id;
TraceEventVCPUID vcpu_id;
const char * name; const char * name;
const bool sstate; const bool sstate;
} TraceEvent; } TraceEvent;

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 {
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);
} }
} }

View File

@ -19,6 +19,9 @@
#ifndef TRANSLATE_ALL_H #ifndef TRANSLATE_ALL_H
#define TRANSLATE_ALL_H #define TRANSLATE_ALL_H
#include "exec/exec-all.h"
/* translate-all.c */ /* translate-all.c */
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,

1
vl.c
View File

@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp)
os_setup_post(); os_setup_post();
trace_init_vcpu_events();
main_loop(); main_loop();
replay_disable_events(); replay_disable_events();