From 6533dd6e111bb7929f8bf4fe06eadba1c70e6f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 15 Jul 2016 19:08:38 +0200 Subject: [PATCH 1/9] trace: [linux-user] Commandline arguments to control tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Changed const char *trace_file to char *trace_file since it's a heap-allocated string that needs to be freed. This type is also returned by trace_opt_parse() and used in vl.c. --Stefan] Signed-off-by: Lluís Vilanova Message-id: 146860251784.30668.17339867835129075077.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- linux-user/main.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 617a179f14..a053c22dee 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -24,6 +24,7 @@ #include "qapi/error.h" #include "qemu.h" #include "qemu/path.h" +#include "qemu/config-file.h" #include "qemu/cutils.h" #include "qemu/help_option.h" #include "cpu.h" @@ -33,6 +34,8 @@ #include "qemu/envlist.h" #include "elf.h" #include "exec/log.h" +#include "trace/control.h" +#include "glib-compat.h" char *exec_path; @@ -4001,6 +4004,13 @@ static void handle_arg_version(const char *arg) 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 { const char *argv; const char *env; @@ -4048,6 +4058,8 @@ static const struct qemu_argument arg_table[] = { "", "log system calls"}, {"seed", "QEMU_RAND_SEED", true, handle_arg_randseed, "", "Seed for pseudo-random number generator"}, + {"trace", "QEMU_TRACE", true, handle_arg_trace, + "", "[[enable=]][,events=][,file=]"}, {"version", "QEMU_VERSION", false, handle_arg_version, "", "display version information and exit"}, {NULL, NULL, false, NULL, NULL, NULL} @@ -4237,8 +4249,15 @@ int main(int argc, char **argv, char **envp) srand(time(NULL)); + qemu_add_opts(&qemu_trace_opts); + optind = parse_args(argc, argv); + if (!trace_init_backends()) { + exit(1); + } + trace_init_file(trace_file); + /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); From 6913e79c3677a4282203fdd79af7927a94d0427e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 15 Jul 2016 19:08:43 +0200 Subject: [PATCH 2/9] trace: [bsd-user] Commandline arguments to control tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Changed const char *trace_file to char *trace_file since it's a heap-allocated string that needs to be freed. This type is also returned by trace_opt_parse() and used in vl.c. Also fixed coding style on for(;;) and else statement as suggested by Eric Blake since the patch modifies these lines or close enough. --Stefan] Signed-off-by: Lluís Vilanova Message-id: 146860252322.30668.18276041739086338328.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- bsd-user/main.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 4819b9ec63..6d6e3e335a 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu.h" +#include "qemu/config-file.h" #include "qemu/path.h" #include "qemu/help_option.h" /* For tb_lock */ @@ -30,6 +31,8 @@ #include "qemu/timer.h" #include "qemu/envlist.h" #include "exec/log.h" +#include "trace/control.h" +#include "glib-compat.h" int singlestep; unsigned long mmap_min_addr; @@ -687,6 +690,8 @@ static void usage(void) "-p pagesize set the host page size to 'pagesize'\n" "-singlestep always run in singlestep mode\n" "-strace log system calls\n" + "-trace [[enable=]][,events=][,file=]\n" + " specify tracing options\n" "\n" "Environment variables:\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; char **target_environ, **wrk; envlist_t *envlist = NULL; + char *trace_file = NULL; bsd_type = target_openbsd; if (argc <= 1) @@ -754,8 +760,10 @@ int main(int argc, char **argv) cpu_model = NULL; + qemu_add_opts(&qemu_trace_opts); + optind = 1; - for(;;) { + for (;;) { if (optind >= argc) break; r = argv[optind]; @@ -840,8 +848,10 @@ int main(int argc, char **argv) singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; - } else - { + } else if (!strcmp(r, "trace")) { + g_free(trace_file); + trace_file = trace_opt_parse(optarg); + } else { usage(); } } @@ -865,6 +875,11 @@ int main(int argc, char **argv) } filename = argv[optind]; + if (!trace_init_backends()) { + exit(1); + } + trace_init_file(trace_file); + /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); From 17f7ac75df3909c384c18274b41a2a91192599e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:24 +0200 Subject: [PATCH 3/9] trace: Identify events with the 'vcpu' property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new event attribute 'cpu_id' is added to have a separate ID space ('TRACE_VCPU_*') for all events with the 'vcpu' property. These are later used to identify which events are enabled on each vCPU. Signed-off-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/format/events_c.py | 11 +++++++++-- scripts/tracetool/format/events_h.py | 12 +++++++++++- trace/control-internal.h | 12 +++++++++++- trace/control.h | 17 +++++++++++++++++ trace/event-internal.h | 4 +++- 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index 1cc6a49a71..4012063283 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -6,7 +6,7 @@ trace/generated-events.c """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -28,8 +28,15 @@ def generate(events, backend): out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') 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(), + vcpu_id = vcpu_id, name = e.name, sstate = "TRACE_%s_ENABLED" % e.name.upper()) diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index 4529263e00..a9da60b7fa 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -32,13 +32,23 @@ def generate(events, backend): out(' TRACE_EVENT_COUNT', '} 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 for e in events: if 'disable' in e.properties: enabled = 0 else: enabled = 1 - if "tcg-trans" in e.properties: + if "tcg-exec" in e.properties: # a single define for the two "sub-events" out('#define TRACE_%(name)s_ENABLED %(enabled)d', name=e.original.name.upper(), diff --git a/trace/control-internal.h b/trace/control-internal.h index deacc8f894..59bcbb4427 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2014 Lluís Vilanova + * Copyright (C) 2011-2016 Lluís Vilanova * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -38,6 +38,16 @@ static inline TraceEventID trace_event_get_id(TraceEvent *ev) 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) { assert(ev != NULL); diff --git a/trace/control.h b/trace/control.h index 452a800eb2..d7d6500438 100644 --- a/trace/control.h +++ b/trace/control.h @@ -85,6 +85,23 @@ static TraceEventID trace_event_count(void); */ 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: * diff --git a/trace/event-internal.h b/trace/event-internal.h index e4ea2e78a9..5d8fa97ca5 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2012 Lluís Vilanova + * Copyright (C) 2012-2016 Lluís Vilanova * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -16,6 +16,7 @@ /** * TraceEvent: * @id: Unique event identifier. + * @vcpu_id: Unique per-vCPU event identifier. * @name: Event name. * @sstate: Static tracing state. * @@ -23,6 +24,7 @@ */ typedef struct TraceEvent { TraceEventID id; + TraceEventVCPUID vcpu_id; const char * name; const bool sstate; } TraceEvent; From ca66f1a1741907e3f5fede89f04ac993f36130a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:30 +0200 Subject: [PATCH 4/9] disas: Remove unused macro '_' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminates a future compilation error when UI code includes the tracing headers (indirectly pulling "disas/bfd.h" through "qom/cpu.h") and GLib's i18n '_' macro. Signed-off-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- disas/alpha.c | 6 +++--- disas/arm.c | 2 +- disas/i386.c | 2 +- disas/m68k.c | 4 ++-- disas/mips.c | 50 ++++++++++++++++++++++----------------------- disas/ppc.c | 22 ++++++++++---------- disas/sparc.c | 6 +++--- include/disas/bfd.h | 1 - 8 files changed, 46 insertions(+), 47 deletions(-) diff --git a/disas/alpha.c b/disas/alpha.c index 44d00a3635..b7b0ae0d92 100644 --- a/disas/alpha.c +++ b/disas/alpha.c @@ -521,7 +521,7 @@ static unsigned insert_bdisp(unsigned insn, int value, const char **errmsg) { if (errmsg != (const char **)NULL && (value & 3)) - *errmsg = _("branch operand unaligned"); + *errmsg = "branch operand unaligned"; return insn | ((value / 4) & 0x1FFFFF); } @@ -539,7 +539,7 @@ static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) { if (errmsg != (const char **)NULL && (value & 3)) - *errmsg = _("jump hint unaligned"); + *errmsg = "jump hint unaligned"; return insn | ((value / 4) & 0x3FFF); } @@ -556,7 +556,7 @@ static unsigned insert_ev6hwjhint(unsigned insn, int value, const char **errmsg) { if (errmsg != (const char **)NULL && (value & 3)) - *errmsg = _("jump hint unaligned"); + *errmsg = "jump hint unaligned"; return insn | ((value / 4) & 0x1FFF); } diff --git a/disas/arm.c b/disas/arm.c index 70da5298a0..32f8ca992f 100644 --- a/disas/arm.c +++ b/disas/arm.c @@ -1817,7 +1817,7 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, func (stream, "e"); break; default: - func (stream, _("")); + func (stream, ""); break; } break; diff --git a/disas/i386.c b/disas/i386.c index c0e717abe3..57145d0a6b 100644 --- a/disas/i386.c +++ b/disas/i386.c @@ -3406,7 +3406,7 @@ static const struct dis386 three_byte_table[][256] = { } }; -#define INTERNAL_DISASSEMBLER_ERROR _("") +#define INTERNAL_DISASSEMBLER_ERROR "" static void ckprefix (void) diff --git a/disas/m68k.c b/disas/m68k.c index 8f74ae1157..8e7c3f76c4 100644 --- a/disas/m68k.c +++ b/disas/m68k.c @@ -1676,7 +1676,7 @@ print_insn_arg (const char *d, (*info->fprintf_func) (info->stream, "%%sfc"); else /* xgettext:c-format */ - (*info->fprintf_func) (info->stream, _(""), fc); + (*info->fprintf_func) (info->stream, "", fc); } break; @@ -1827,7 +1827,7 @@ match_insn_m68k (bfd_vma memaddr, { info->fprintf_func (info->stream, /* xgettext:c-format */ - _("\n"), + "\n", best->name, best->args); info->fprintf_func = save_printer; info->print_address_func = save_print_address; diff --git a/disas/mips.c b/disas/mips.c index 249931b735..97f661a37e 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -4257,7 +4257,7 @@ print_insn_args (const char *d, case '\0': /* xgettext:c-format */ (*info->fprintf_func) (info->stream, - _("# internal error, incomplete extension sequence (+)")); + "# internal error, incomplete extension sequence (+)"); return; case 'A': @@ -4515,7 +4515,7 @@ print_insn_args (const char *d, default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, - _("# internal error, undefined extension sequence (+%c)"), + "# internal error, undefined extension sequence (+%c)", *d); return; } @@ -4875,7 +4875,7 @@ print_insn_args (const char *d, default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, - _("# internal error, undefined modifier(%c)"), + "# internal error, undefined modifier(%c)", *d); return; } @@ -5739,7 +5739,7 @@ print_mips16_insn_arg (char type, /* xgettext:c-format */ (*info->fprintf_func) (info->stream, - _("# internal disassembler error, unrecognised modifier (%c)"), + "# internal disassembler error, unrecognised modifier (%c)", type); abort (); } @@ -5750,51 +5750,51 @@ print_mips_disassembler_options (FILE *stream) { unsigned int i; - fprintf (stream, _("\n\ + fprintf (stream, "\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\ - 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\ - Default: numeric.\n")); + Default: numeric.\n"); - fprintf (stream, _("\n\ + fprintf (stream, "\n\ cp0-names=ARCH Print CP0 register names according to\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\ 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\ - specified ABI.\n")); + specified ABI.\n"); - fprintf (stream, _("\n\ + fprintf (stream, "\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 (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) 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 (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) if (*mips_arch_choices[i].name != '\0') fprintf (stream, " %s", mips_arch_choices[i].name); - fprintf (stream, _("\n")); + fprintf (stream, "\n"); - fprintf (stream, _("\n")); + fprintf (stream, "\n"); } #endif diff --git a/disas/ppc.c b/disas/ppc.c index 478332ba37..052cebe851 100644 --- a/disas/ppc.c +++ b/disas/ppc.c @@ -1120,7 +1120,7 @@ insert_bo (unsigned long insn, const char **errmsg) { if (!valid_bo (value, dialect, 0)) - *errmsg = _("invalid conditional option"); + *errmsg = "invalid conditional option"; return insn | ((value & 0x1f) << 21); } @@ -1148,9 +1148,9 @@ insert_boe (unsigned long insn, const char **errmsg) { if (!valid_bo (value, dialect, 0)) - *errmsg = _("invalid conditional option"); + *errmsg = "invalid conditional option"; 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); } @@ -1182,7 +1182,7 @@ insert_fxm (unsigned long insn, { if (value == 0 || (value & -value) != value) { - *errmsg = _("invalid mask field"); + *errmsg = "invalid mask field"; value = 0; } } @@ -1208,7 +1208,7 @@ insert_fxm (unsigned long insn, /* Any other value on mfcr is an error. */ else if ((insn & (0x3ff << 1)) == 19 << 1) { - *errmsg = _("ignoring invalid mfcr mask"); + *errmsg = "ignoring invalid mfcr mask"; value = 0; } @@ -1258,7 +1258,7 @@ insert_mbe (unsigned long insn, if (uval == 0) { - *errmsg = _("illegal bitmask"); + *errmsg = "illegal bitmask"; return insn; } @@ -1293,7 +1293,7 @@ insert_mbe (unsigned long insn, me = 32; if (count != 2 && (count != 0 || ! last)) - *errmsg = _("illegal bitmask"); + *errmsg = "illegal bitmask"; return insn | (mb << 6) | ((me - 1) << 1); } @@ -1413,7 +1413,7 @@ insert_ram (unsigned long insn, const char **errmsg) { if ((unsigned long) value >= ((insn >> 21) & 0x1f)) - *errmsg = _("index register in load range"); + *errmsg = "index register in load range"; return insn | ((value & 0x1f) << 16); } @@ -1429,7 +1429,7 @@ insert_raq (unsigned long insn, long rtvalue = (insn & RT_MASK) >> 21; 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); } @@ -1444,7 +1444,7 @@ insert_ras (unsigned long insn, const char **errmsg) { if (value == 0) - *errmsg = _("invalid register operand when updating"); + *errmsg = "invalid register operand when updating"; return insn | ((value & 0x1f) << 16); } @@ -1526,7 +1526,7 @@ insert_sprg (unsigned long insn, if (value > 7 || (value > 3 && (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 user mode. Anything else must use spr 272..279. */ diff --git a/disas/sparc.c b/disas/sparc.c index 64bba8df27..f120f4e86d 100644 --- a/disas/sparc.c +++ b/disas/sparc.c @@ -2494,7 +2494,7 @@ compare_opcodes (const void * a, const void * b) fprintf (stderr, /* 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->lose &= ~op0->match; lose0 = op0->lose; @@ -2505,7 +2505,7 @@ compare_opcodes (const void * a, const void * b) fprintf (stderr, /* 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->lose &= ~op1->match; lose1 = op1->lose; @@ -2555,7 +2555,7 @@ compare_opcodes (const void * a, const void * b) else fprintf (stderr, /* 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); } diff --git a/include/disas/bfd.h b/include/disas/bfd.h index 64c9544ed7..231e5fbf91 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -477,7 +477,6 @@ int generic_symbol_at_address(bfd_vma, struct disassemble_info *); (INFO).disassembler_options = NULL, \ (INFO).insn_info_valid = 0 -#define _(x) x #define ATTRIBUTE_UNUSED __attribute__((unused)) /* from libbfd */ From e1d6e0a4c0e23b30501b887211f1fa6e0eb799a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:35 +0200 Subject: [PATCH 5/9] trace: Cosmetic changes on fast-path tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- trace/control-internal.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/trace/control-internal.h b/trace/control-internal.h index 59bcbb4427..b326d88d72 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -60,14 +60,17 @@ static inline bool trace_event_get_state_static(TraceEvent *ev) 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]; } 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); } From 4815185902971c41fcdd700fa1fc3e1d9299900f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:41 +0200 Subject: [PATCH 6/9] trace: Add per-vCPU tracing states for events with the 'vcpu' property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each vCPU gets a 'trace_dstate' bitmap to control the per-vCPU dynamic tracing state of events with the 'vcpu' property. Signed-off-by: Lluís Vilanova Signed-off-by: Stefan Hajnoczi --- bsd-user/main.c | 1 + include/qom/cpu.h | 6 ++++ linux-user/main.c | 1 + qom/cpu.c | 1 + stubs/Makefile.objs | 1 + stubs/trace-control.c | 28 ++++++++++++++++++ trace/Makefile.objs | 4 +++ trace/control-internal.h | 30 ++++++++++++++----- trace/control-target.c | 53 ++++++++++++++++++++++++++++++++++ trace/control.c | 29 +++++++++++++++++-- trace/control.h | 62 +++++++++++++++++++++++++++++++++++++++- translate-all.h | 3 ++ vl.c | 1 + 13 files changed, 210 insertions(+), 10 deletions(-) create mode 100644 stubs/trace-control.c create mode 100644 trace/control-target.c diff --git a/bsd-user/main.c b/bsd-user/main.c index 6d6e3e335a..315ba1d10c 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -1131,6 +1131,7 @@ int main(int argc, char **argv) gdbserver_start (gdbstub_port); gdb_handlesig(cpu, 0); } + trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index a6c6ed8b57..cbcd64c92b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -24,8 +24,10 @@ #include "disas/bfd.h" #include "exec/hwaddr.h" #include "exec/memattrs.h" +#include "qemu/bitmap.h" #include "qemu/queue.h" #include "qemu/thread.h" +#include "trace/generated-events.h" typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, void *opaque); @@ -280,6 +282,7 @@ struct qemu_work_item { * @kvm_fd: vCPU file descriptor for KVM. * @work_mutex: Lock to prevent multiple access to queued_work_*. * @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. */ @@ -347,6 +350,9 @@ struct CPUState { struct KVMState *kvm_state; 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. */ int cpu_index; /* used by alpha TCG */ uint32_t halted; /* used by alpha, cris, ppc TCG */ diff --git a/linux-user/main.c b/linux-user/main.c index a053c22dee..462e820469 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4810,6 +4810,7 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(cpu, 0); } + trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/qom/cpu.c b/qom/cpu.c index a9727a1e64..42b5631c7c 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -345,6 +345,7 @@ static void cpu_common_initfn(Object *obj) qemu_mutex_init(&cpu->work_mutex); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); + bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT); } static void cpu_common_finalize(Object *obj) diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 7cdcad4fdb..55edd15d71 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -30,6 +30,7 @@ stub-obj-y += runstate-check.o stub-obj-y += set-fd-handler.o stub-obj-y += slirp.o stub-obj-y += sysbus.o +stub-obj-y += trace-control.o stub-obj-y += uuid.o stub-obj-y += vm-stop.o stub-obj-y += vmstate.o diff --git a/stubs/trace-control.c b/stubs/trace-control.c new file mode 100644 index 0000000000..fe59836fce --- /dev/null +++ b/stubs/trace-control.c @@ -0,0 +1,28 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2014-2016 Lluís Vilanova + * + * 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(); +} diff --git a/trace/Makefile.objs b/trace/Makefile.objs index cbe188e484..4d91b3b833 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -15,6 +15,7 @@ $(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%) # Auto-generated event descriptions for LTTng ust code ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust) + $(obj)/generated-ust-provider.h: $(obj)/generated-ust-provider.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ $(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.c: $(obj)/generated-ust.c + 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 # rule file. So we use '.dtrace' instead ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) + $(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ $(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_UST) += generated-ust.o util-obj-y += control.o +target-obj-y += control-target.o util-obj-y += qmp.o diff --git a/trace/control-internal.h b/trace/control-internal.h index b326d88d72..a4e5f4aa06 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -10,8 +10,13 @@ #ifndef TRACE__CONTROL_INTERNAL_H #define TRACE__CONTROL_INTERNAL_H +#include /* size_t */ + +#include "qom/cpu.h" + + extern TraceEvent trace_events[]; -extern bool trace_events_dstate[]; +extern uint16_t trace_events_dstate[]; extern int trace_events_enabled_count; @@ -74,13 +79,24 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev) 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); - assert(ev != NULL); - assert(trace_event_get_state_static(ev)); - trace_events_enabled_count += state - trace_events_dstate[id]; - trace_events_dstate[id] = state; + /* it's on fast path, avoid consistency checks (asserts) */ + if (unlikely(trace_events_enabled_count)) { + return test_bit(id, vcpu->trace_dstate); + } else { + 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 */ diff --git a/trace/control-target.c b/trace/control-target.c new file mode 100644 index 0000000000..74c029accc --- /dev/null +++ b/trace/control-target.c @@ -0,0 +1,53 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2014-2016 Lluís Vilanova + * + * 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]--; + } + } +} diff --git a/trace/control.c b/trace/control.c index 86de8b9983..d173c09f44 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2014 Lluís Vilanova + * Copyright (C) 2011-2016 Lluís Vilanova * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -25,7 +25,14 @@ #include "monitor/monitor.h" 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 = { .name = "trace", @@ -135,7 +142,10 @@ static void do_trace_enable_events(const char *line_buf) TraceEvent *ev = NULL; while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { if (trace_event_get_state_static(ev)) { + /* start tracing */ trace_event_set_state_dynamic(ev, enable); + /* mark for late vCPU init */ + trace_events_dstate_init[ev->id] = true; } } } else { @@ -147,7 +157,10 @@ static void do_trace_enable_events(const char *line_buf) error_report("WARNING: trace event '%s' is not traceable", line_ptr); } else { + /* start tracing */ 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; } + +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); + } + } +} diff --git a/trace/control.h b/trace/control.h index d7d6500438..0413b28769 100644 --- a/trace/control.h +++ b/trace/control.h @@ -123,6 +123,23 @@ static const char * trace_event_get_name(TraceEvent *ev); #define trace_event_get_state(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: * @id: Event identifier. @@ -138,9 +155,18 @@ static bool trace_event_get_state_static(TraceEvent *ev); * trace_event_get_state_dynamic: * * 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); +/** + * 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: * @@ -154,14 +180,39 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); } \ } 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: * * 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 */ -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); @@ -218,6 +269,15 @@ extern QemuOptsList qemu_trace_opts; */ 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" #endif /* TRACE__CONTROL_H */ diff --git a/translate-all.h b/translate-all.h index ce6071bd9b..ba8e4d63c4 100644 --- a/translate-all.h +++ b/translate-all.h @@ -19,6 +19,9 @@ #ifndef TRANSLATE_ALL_H #define TRANSLATE_ALL_H +#include "exec/exec-all.h" + + /* translate-all.c */ 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, diff --git a/vl.c b/vl.c index d3ec5320ea..a455947b4f 100644 --- a/vl.c +++ b/vl.c @@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp) os_setup_post(); + trace_init_vcpu_events(); main_loop(); replay_disable_events(); From 40b9cd25f789e02145fda5e1f3fde7e7dd9e3b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:46 +0200 Subject: [PATCH 7/9] trace: Conditionally trace events based on their per-vCPU state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Events with the 'vcpu' property are conditionally emitted according to their per-vCPU state. Other events are emitted normally based on their global tracing state. Note that the per-vCPU condition check applies to all tracing backends. Signed-off-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/dtrace.py | 4 ++-- scripts/tracetool/backend/ftrace.py | 20 ++++++++++---------- scripts/tracetool/backend/log.py | 26 ++++++++++++++++---------- scripts/tracetool/backend/simple.py | 13 ++++++++++--- scripts/tracetool/backend/ust.py | 4 ++-- scripts/tracetool/format/h.py | 19 +++++++++++++++++-- 6 files changed, 57 insertions(+), 29 deletions(-) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index fabfe99881..ab9ecfab30 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -6,7 +6,7 @@ DTrace/SystemTAP backend. """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -41,6 +41,6 @@ def generate_h_begin(events): def generate_h(event): - out(' QEMU_%(uppername)s(%(argnames)s);', + out(' QEMU_%(uppername)s(%(argnames)s);', uppername=event.name.upper(), argnames=", ".join(event.args.names())) diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py index d798c71347..80dcf30478 100644 --- a/scripts/tracetool/backend/ftrace.py +++ b/scripts/tracetool/backend/ftrace.py @@ -30,17 +30,17 @@ def generate_h(event): if len(event.args) > 0: argnames = ", " + argnames - out(' {', - ' char ftrace_buf[MAX_TRACE_STRLEN];', - ' int unused __attribute__ ((unused));', - ' int trlen;', - ' if (trace_event_get_state(%(event_id)s)) {', - ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', - ' "%(name)s " %(fmt)s "\\n" %(argnames)s);', - ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', - ' unused = write(trace_marker_fd, ftrace_buf, trlen);', + out(' {', + ' char ftrace_buf[MAX_TRACE_STRLEN];', + ' int unused __attribute__ ((unused));', + ' int trlen;', + ' if (trace_event_get_state(%(event_id)s)) {', + ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', + ' "%(name)s " %(fmt)s "\\n" %(argnames)s);', + ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', + ' unused = write(trace_marker_fd, ftrace_buf, trlen);', + ' }', ' }', - ' }', name=event.name, args=event.args, event_id="TRACE_" + event.name.upper(), diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py index e409b7326e..b3ff064011 100644 --- a/scripts/tracetool/backend/log.py +++ b/scripts/tracetool/backend/log.py @@ -6,7 +6,7 @@ Stderr built-in backend. """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -30,15 +30,21 @@ def generate_h(event): if len(event.args) > 0: argnames = ", " + argnames - out(' if (trace_event_get_state(%(event_id)s)) {', - ' struct timeval _now;', - ' gettimeofday(&_now, NULL);', - ' qemu_log_mask(LOG_TRACE, "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",', - ' getpid(),', - ' (size_t)_now.tv_sec, (size_t)_now.tv_usec', - ' %(argnames)s);', - ' }', - 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)" % ("TRACE_" + event.name.upper()) + + out(' if (%(cond)s) {', + ' struct timeval _now;', + ' gettimeofday(&_now, NULL);', + ' qemu_log_mask(LOG_TRACE, "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",', + ' getpid(),', + ' (size_t)_now.tv_sec, (size_t)_now.tv_usec', + ' %(argnames)s);', + ' }', + cond=cond, name=event.name, fmt=event.fmt.rstrip("\n"), argnames=argnames) diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index 3246c20015..1bccada63d 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -36,7 +36,7 @@ def generate_h_begin(events): def generate_h(event): - out(' _simple_%(api)s(%(args)s);', + out(' _simple_%(api)s(%(args)s);', api=event.api(), args=", ".join(event.args.names())) @@ -68,16 +68,23 @@ def generate_c(event): if len(event.args) == 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('', - ' if (!trace_event_get_state(%(event_id)s)) {', + ' if (!%(cond)s) {', ' return;', ' }', '', ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', ' return; /* Trace Buffer Full, Event Dropped ! */', ' }', - event_id='TRACE_' + event.name.upper(), + cond=cond, + event_id=event_id, size_str=sizestr) if len(event.args) > 0: diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py index 2f8f44abde..ed4c227f69 100644 --- a/scripts/tracetool/backend/ust.py +++ b/scripts/tracetool/backend/ust.py @@ -6,7 +6,7 @@ LTTng User Space Tracing backend. """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -30,6 +30,6 @@ def generate_h(event): if len(event.args) > 0: argnames = ", " + argnames - out(' tracepoint(qemu, %(name)s%(tp_args)s);', + out(' tracepoint(qemu, %(name)s%(tp_args)s);', name=event.name, tp_args=argnames) diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 0835406216..3763e9aecb 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -23,21 +23,36 @@ def generate(events, backend): '#define TRACE__GENERATED_TRACERS_H', '', '#include "qemu-common.h"', + '#include "trace/control.h"', '') backend.generate_begin(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('', 'static inline void %(api)s(%(args)s)', '{', + ' if (%(cond)s) {', api=e.api(), - args=e.args) + args=e.args, + cond=cond) if "disable" not in e.properties: backend.generate(e) - out('}') + out(' }', + '}') backend.generate_end(events) From bd71211d556aac5451696785fbe29be7f70bed05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:51 +0200 Subject: [PATCH 8/9] trace: Allow event name pattern in "info trace-events" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Homogenizes the command capabilities with QMP. Signed-off-by: Lluís Vilanova Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- hmp-commands-info.hx | 8 +++++--- hmp.h | 1 + monitor.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 7da9e6cb91..3d07ca6a77 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -646,10 +646,12 @@ ETEXI { .name = "trace-events", - .args_type = "", - .params = "", - .help = "show available trace-events & their state", + .args_type = "name:s?", + .params = "[name]", + .help = "show available trace-events & their state " + "(name: event name pattern)", .mhandler.cmd = hmp_info_trace_events, + .command_completion = info_trace_events_completion, }, STEXI diff --git a/hmp.h b/hmp.h index f5d9749339..0876ec03a1 100644 --- a/hmp.h +++ b/hmp.h @@ -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_del_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 watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str); diff --git a/monitor.c b/monitor.c index d0ff246a16..ab31725342 100644 --- a/monitor.c +++ b/monitor.c @@ -1065,8 +1065,20 @@ static void hmp_info_cpustats(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"); + TraceEventInfoList *events; TraceEventInfoList *elem; + Error *local_err = NULL; + + if (name == NULL) { + name = "*"; + } + + events = qmp_trace_event_get_state(name, &local_err); + if (local_err) { + error_report_err(local_err); + return; + } for (elem = events; elem != NULL; elem = elem->next) { monitor_printf(mon, "%s : state %u\n", @@ -3296,6 +3308,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) { size_t len; From 77e2b17272963c09e309315903f3781dbdd85341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 11 Jul 2016 12:53:57 +0200 Subject: [PATCH 9/9] trace: Add QAPI/QMP interfaces to query and control per-vCPU tracing state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Reviewed-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- hmp-commands-info.hx | 6 +- hmp-commands.hx | 7 +- monitor.c | 17 ++++- qapi/trace.json | 33 ++++++++-- qmp-commands.hx | 35 +++++++++- trace/qmp.c | 154 ++++++++++++++++++++++++++++++++++--------- 6 files changed, 206 insertions(+), 46 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 3d07ca6a77..74446c669e 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -646,10 +646,10 @@ ETEXI { .name = "trace-events", - .args_type = "name:s?", - .params = "[name]", + .args_type = "name:s?,vcpu:i?", + .params = "[name] [vcpu]", .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, .command_completion = info_trace_events_completion, }, diff --git a/hmp-commands.hx b/hmp-commands.hx index 98b4b1a82c..848efee5d1 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -281,9 +281,10 @@ ETEXI { .name = "trace-event", - .args_type = "name:s,option:b", - .params = "name on|off", - .help = "changes status of a specific trace event", + .args_type = "name:s,option:b,vcpu:i?", + .params = "name on|off [vcpu]", + .help = "changes status of a specific trace event " + "(vcpu: vCPU to set, default is all)", .mhandler.cmd = hmp_trace_event, .command_completion = trace_event_completion, }, diff --git a/monitor.c b/monitor.c index ab31725342..c1591f286d 100644 --- a/monitor.c +++ b/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"); 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; - 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) { 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) { 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; Error *local_err = NULL; @@ -1073,8 +1082,12 @@ static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) if (name == NULL) { 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) { error_report_err(local_err); return; diff --git a/qapi/trace.json b/qapi/trace.json index 01b0a52a7e..e87214677c 100644 --- a/qapi/trace.json +++ b/qapi/trace.json @@ -1,6 +1,6 @@ # -*- mode: python -*- # -# Copyright (C) 2011-2014 Lluís Vilanova +# Copyright (C) 2011-2016 Lluís Vilanova # # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. @@ -29,11 +29,15 @@ # # @name: Event name. # @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 ## { 'struct': 'TraceEventInfo', - 'data': {'name': 'str', 'state': 'TraceEventState'} } + 'data': {'name': 'str', 'state': 'TraceEventState', 'vcpu': 'bool'} } ## # @trace-event-get-state: @@ -41,13 +45,23 @@ # Query the state of events. # # @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 # +# 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 ## { 'command': 'trace-event-get-state', - 'data': {'name': 'str'}, + 'data': {'name': 'str', '*vcpu': 'int'}, 'returns': ['TraceEventInfo'] } ## @@ -58,8 +72,19 @@ # @name: Event name pattern (case-sensitive glob). # @enable: Whether to enable tracing. # @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 ## { 'command': 'trace-event-set-state', - 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool'} } + 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool', + '*vcpu': 'int'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index c46c65ce2d..496d73c275 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -4715,7 +4715,7 @@ EQMP { .name = "trace-event-get-state", - .args_type = "name:s", + .args_type = "name:s,vcpu:i?", .mhandler.cmd_new = qmp_marshal_trace_event_get_state, }, @@ -4725,6 +4725,20 @@ trace-event-get-state 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: -> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } } @@ -4733,7 +4747,7 @@ EQMP { .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, }, @@ -4743,6 +4757,23 @@ trace-event-set-state 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: -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } 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 + * Copyright (C) 2014-2016 Lluís Vilanova * * 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) { - TraceEventInfoList *events = NULL; - bool found = false; - TraceEvent *ev; + 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; + 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; - } - } - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); + /* Check provided vcpu */ + cpu = get_cpu(has_vcpu, vcpu, &err); + if (err) { + error_propagate(errp, err); 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; 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); } }