diff options
51 files changed, 732 insertions, 275 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1d0e2c39ce..83e0f1347d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1027,6 +1027,7 @@ F: async.c F: aio-*.c F: block/io.c F: migration/block* +F: include/block/aio.h T: git git://github.com/stefanha/qemu.git block Block Jobs diff --git a/aio-posix.c b/aio-posix.c index 6006122e0b..43162a9f29 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -485,12 +485,13 @@ bool aio_poll(AioContext *ctx, bool blocking) return progress; } -void aio_context_setup(AioContext *ctx, Error **errp) +void aio_context_setup(AioContext *ctx) { #ifdef CONFIG_EPOLL_CREATE1 assert(!ctx->epollfd); ctx->epollfd = epoll_create1(EPOLL_CLOEXEC); if (ctx->epollfd == -1) { + fprintf(stderr, "Failed to create epoll instance: %s", strerror(errno)); ctx->epoll_available = false; } else { ctx->epoll_available = true; diff --git a/aio-win32.c b/aio-win32.c index 6aaa32a147..c8c249e260 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -371,6 +371,6 @@ bool aio_poll(AioContext *ctx, bool blocking) return progress; } -void aio_context_setup(AioContext *ctx, Error **errp) +void aio_context_setup(AioContext *ctx) { } @@ -29,6 +29,7 @@ #include "block/thread-pool.h" #include "qemu/main-loop.h" #include "qemu/atomic.h" +#include "block/raw-aio.h" /***********************************************************/ /* bottom halves (can be seen as timers which expire ASAP) */ @@ -217,7 +218,7 @@ aio_ctx_check(GSource *source) for (bh = ctx->first_bh; bh; bh = bh->next) { if (!bh->deleted && bh->scheduled) { return true; - } + } } return aio_pending(ctx) || (timerlistgroup_deadline_ns(&ctx->tlg) == 0); } @@ -242,6 +243,14 @@ aio_ctx_finalize(GSource *source) qemu_bh_delete(ctx->notify_dummy_bh); thread_pool_free(ctx->thread_pool); +#ifdef CONFIG_LINUX_AIO + if (ctx->linux_aio) { + laio_detach_aio_context(ctx->linux_aio, ctx); + laio_cleanup(ctx->linux_aio); + ctx->linux_aio = NULL; + } +#endif + qemu_mutex_lock(&ctx->bh_lock); while (ctx->first_bh) { QEMUBH *next = ctx->first_bh->next; @@ -282,6 +291,17 @@ ThreadPool *aio_get_thread_pool(AioContext *ctx) return ctx->thread_pool; } +#ifdef CONFIG_LINUX_AIO +LinuxAioState *aio_get_linux_aio(AioContext *ctx) +{ + if (!ctx->linux_aio) { + ctx->linux_aio = laio_init(); + laio_attach_aio_context(ctx->linux_aio, ctx); + } + return ctx->linux_aio; +} +#endif + void aio_notify(AioContext *ctx) { /* Write e.g. bh->scheduled before reading ctx->notify_me. Pairs @@ -327,14 +347,10 @@ AioContext *aio_context_new(Error **errp) { int ret; AioContext *ctx; - Error *local_err = NULL; ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext)); - aio_context_setup(ctx, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; - } + aio_context_setup(ctx); + ret = event_notifier_init(&ctx->notifier, false); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to initialize event notifier"); @@ -345,6 +361,9 @@ AioContext *aio_context_new(Error **errp) false, (EventNotifierHandler *) event_notifier_dummy_cb); +#ifdef CONFIG_LINUX_AIO + ctx->linux_aio = NULL; +#endif ctx->thread_pool = NULL; qemu_mutex_init(&ctx->bh_lock); rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx); diff --git a/block/linux-aio.c b/block/linux-aio.c index 5c104bd3cd..de3548f2ab 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -28,8 +28,6 @@ */ #define MAX_EVENTS 128 -#define MAX_QUEUED_IO 128 - struct qemu_laiocb { BlockAIOCB common; Coroutine *co; @@ -44,12 +42,15 @@ struct qemu_laiocb { typedef struct { int plugged; - unsigned int n; + unsigned int in_queue; + unsigned int in_flight; bool blocked; QSIMPLEQ_HEAD(, qemu_laiocb) pending; } LaioQueue; struct LinuxAioState { + AioContext *aio_context; + io_context_t ctx; EventNotifier e; @@ -129,6 +130,7 @@ static void qemu_laio_completion_bh(void *opaque) s->event_max = 0; return; /* no more events */ } + s->io_q.in_flight -= s->event_max; } /* Reschedule so nested event loops see currently pending completions */ @@ -190,7 +192,8 @@ static void ioq_init(LaioQueue *io_q) { QSIMPLEQ_INIT(&io_q->pending); io_q->plugged = 0; - io_q->n = 0; + io_q->in_queue = 0; + io_q->in_flight = 0; io_q->blocked = false; } @@ -198,14 +201,17 @@ static void ioq_submit(LinuxAioState *s) { int ret, len; struct qemu_laiocb *aiocb; - struct iocb *iocbs[MAX_QUEUED_IO]; + struct iocb *iocbs[MAX_EVENTS]; QSIMPLEQ_HEAD(, qemu_laiocb) completed; do { + if (s->io_q.in_flight >= MAX_EVENTS) { + break; + } len = 0; QSIMPLEQ_FOREACH(aiocb, &s->io_q.pending, next) { iocbs[len++] = &aiocb->iocb; - if (len == MAX_QUEUED_IO) { + if (s->io_q.in_flight + len >= MAX_EVENTS) { break; } } @@ -218,24 +224,24 @@ static void ioq_submit(LinuxAioState *s) abort(); } - s->io_q.n -= ret; + s->io_q.in_flight += ret; + s->io_q.in_queue -= ret; aiocb = container_of(iocbs[ret - 1], struct qemu_laiocb, iocb); QSIMPLEQ_SPLIT_AFTER(&s->io_q.pending, aiocb, next, &completed); } while (ret == len && !QSIMPLEQ_EMPTY(&s->io_q.pending)); - s->io_q.blocked = (s->io_q.n > 0); + s->io_q.blocked = (s->io_q.in_queue > 0); } void laio_io_plug(BlockDriverState *bs, LinuxAioState *s) { - assert(!s->io_q.plugged); - s->io_q.plugged = 1; + s->io_q.plugged++; } void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s) { assert(s->io_q.plugged); - s->io_q.plugged = 0; - if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { + if (--s->io_q.plugged == 0 && + !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { ioq_submit(s); } } @@ -263,9 +269,10 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e)); QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next); - s->io_q.n++; + s->io_q.in_queue++; if (!s->io_q.blocked && - (!s->io_q.plugged || s->io_q.n >= MAX_QUEUED_IO)) { + (!s->io_q.plugged || + s->io_q.in_flight + s->io_q.in_queue >= MAX_EVENTS)) { ioq_submit(s); } @@ -325,6 +332,7 @@ void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context) void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context) { + s->aio_context = new_context; s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s); aio_set_event_notifier(new_context, &s->e, false, qemu_laio_completion_cb); diff --git a/block/raw-posix.c b/block/raw-posix.c index d1c3bd8e47..20f4d7aa8d 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -32,7 +32,7 @@ #include "trace.h" #include "block/thread-pool.h" #include "qemu/iov.h" -#include "raw-aio.h" +#include "block/raw-aio.h" #include "qapi/util.h" #include "qapi/qmp/qstring.h" @@ -137,10 +137,6 @@ typedef struct BDRVRawState { int open_flags; size_t buf_align; -#ifdef CONFIG_LINUX_AIO - int use_aio; - LinuxAioState *aio_ctx; -#endif #ifdef CONFIG_XFS bool is_xfs:1; #endif @@ -154,9 +150,6 @@ typedef struct BDRVRawState { typedef struct BDRVRawReopenState { int fd; int open_flags; -#ifdef CONFIG_LINUX_AIO - int use_aio; -#endif } BDRVRawReopenState; static int fd_open(BlockDriverState *bs); @@ -374,58 +367,15 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags) } } -static void raw_detach_aio_context(BlockDriverState *bs) -{ #ifdef CONFIG_LINUX_AIO - BDRVRawState *s = bs->opaque; - - if (s->use_aio) { - laio_detach_aio_context(s->aio_ctx, bdrv_get_aio_context(bs)); - } -#endif -} - -static void raw_attach_aio_context(BlockDriverState *bs, - AioContext *new_context) +static bool raw_use_aio(int bdrv_flags) { -#ifdef CONFIG_LINUX_AIO - BDRVRawState *s = bs->opaque; - - if (s->use_aio) { - laio_attach_aio_context(s->aio_ctx, new_context); - } -#endif -} - -#ifdef CONFIG_LINUX_AIO -static int raw_set_aio(LinuxAioState **aio_ctx, int *use_aio, int bdrv_flags) -{ - int ret = -1; - assert(aio_ctx != NULL); - assert(use_aio != NULL); /* * Currently Linux do AIO only for files opened with O_DIRECT * specified so check NOCACHE flag too */ - if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) == - (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) { - - /* if non-NULL, laio_init() has already been run */ - if (*aio_ctx == NULL) { - *aio_ctx = laio_init(); - if (!*aio_ctx) { - goto error; - } - } - *use_aio = 1; - } else { - *use_aio = 0; - } - - ret = 0; - -error: - return ret; + return (bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) == + (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO); } #endif @@ -494,13 +444,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, s->fd = fd; #ifdef CONFIG_LINUX_AIO - if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) { - qemu_close(fd); - ret = -errno; - error_setg_errno(errp, -ret, "Could not set AIO state"); - goto fail; - } - if (!s->use_aio && (bdrv_flags & BDRV_O_NATIVE_AIO)) { + if (!raw_use_aio(bdrv_flags) && (bdrv_flags & BDRV_O_NATIVE_AIO)) { error_setg(errp, "aio=native was specified, but it requires " "cache.direct=on, which was not specified."); ret = -EINVAL; @@ -567,8 +511,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } #endif - raw_attach_aio_context(bs, bdrv_get_aio_context(bs)); - ret = 0; fail: if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { @@ -603,18 +545,6 @@ static int raw_reopen_prepare(BDRVReopenState *state, state->opaque = g_new0(BDRVRawReopenState, 1); raw_s = state->opaque; -#ifdef CONFIG_LINUX_AIO - raw_s->use_aio = s->use_aio; - - /* we can use s->aio_ctx instead of a copy, because the use_aio flag is - * valid in the 'false' condition even if aio_ctx is set, and raw_set_aio() - * won't override aio_ctx if aio_ctx is non-NULL */ - if (raw_set_aio(&s->aio_ctx, &raw_s->use_aio, state->flags)) { - error_setg(errp, "Could not set AIO state"); - return -1; - } -#endif - if (s->type == FTYPE_CD) { raw_s->open_flags |= O_NONBLOCK; } @@ -689,9 +619,6 @@ static void raw_reopen_commit(BDRVReopenState *state) qemu_close(s->fd); s->fd = raw_s->fd; -#ifdef CONFIG_LINUX_AIO - s->use_aio = raw_s->use_aio; -#endif g_free(state->opaque); state->opaque = NULL; @@ -1329,9 +1256,10 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, if (!bdrv_qiov_is_aligned(bs, qiov)) { type |= QEMU_AIO_MISALIGNED; #ifdef CONFIG_LINUX_AIO - } else if (s->use_aio) { + } else if (bs->open_flags & BDRV_O_NATIVE_AIO) { + LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); assert(qiov->size == bytes); - return laio_co_submit(bs, s->aio_ctx, s->fd, offset, qiov, type); + return laio_co_submit(bs, aio, s->fd, offset, qiov, type); #endif } } @@ -1357,9 +1285,9 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset, static void raw_aio_plug(BlockDriverState *bs) { #ifdef CONFIG_LINUX_AIO - BDRVRawState *s = bs->opaque; - if (s->use_aio) { - laio_io_plug(bs, s->aio_ctx); + if (bs->open_flags & BDRV_O_NATIVE_AIO) { + LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); + laio_io_plug(bs, aio); } #endif } @@ -1367,9 +1295,9 @@ static void raw_aio_plug(BlockDriverState *bs) static void raw_aio_unplug(BlockDriverState *bs) { #ifdef CONFIG_LINUX_AIO - BDRVRawState *s = bs->opaque; - if (s->use_aio) { - laio_io_unplug(bs, s->aio_ctx); + if (bs->open_flags & BDRV_O_NATIVE_AIO) { + LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); + laio_io_unplug(bs, aio); } #endif } @@ -1389,13 +1317,6 @@ static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - raw_detach_aio_context(bs); - -#ifdef CONFIG_LINUX_AIO - if (s->use_aio) { - laio_cleanup(s->aio_ctx); - } -#endif if (s->fd >= 0) { qemu_close(s->fd); s->fd = -1; @@ -1954,9 +1875,6 @@ BlockDriver bdrv_file = { .bdrv_get_allocated_file_size = raw_get_allocated_file_size, - .bdrv_detach_aio_context = raw_detach_aio_context, - .bdrv_attach_aio_context = raw_attach_aio_context, - .create_opts = &raw_create_opts, }; @@ -2402,9 +2320,6 @@ static BlockDriver bdrv_host_device = { .bdrv_probe_blocksizes = hdev_probe_blocksizes, .bdrv_probe_geometry = hdev_probe_geometry, - .bdrv_detach_aio_context = raw_detach_aio_context, - .bdrv_attach_aio_context = raw_attach_aio_context, - /* generic scsi device */ #ifdef __linux__ .bdrv_aio_ioctl = hdev_aio_ioctl, @@ -2524,9 +2439,6 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_get_allocated_file_size = raw_get_allocated_file_size, - .bdrv_detach_aio_context = raw_detach_aio_context, - .bdrv_attach_aio_context = raw_attach_aio_context, - /* removable device support */ .bdrv_is_inserted = cdrom_is_inserted, .bdrv_eject = cdrom_eject, @@ -2657,9 +2569,6 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_get_allocated_file_size = raw_get_allocated_file_size, - .bdrv_detach_aio_context = raw_detach_aio_context, - .bdrv_attach_aio_context = raw_attach_aio_context, - /* removable device support */ .bdrv_is_inserted = cdrom_is_inserted, .bdrv_eject = cdrom_eject, diff --git a/block/raw-win32.c b/block/raw-win32.c index 62edb1a6cc..9b813d99ae 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -27,7 +27,7 @@ #include "qemu/timer.h" #include "block/block_int.h" #include "qemu/module.h" -#include "raw-aio.h" +#include "block/raw-aio.h" #include "trace.h" #include "block/thread-pool.h" #include "qemu/iov.h" diff --git a/block/win32-aio.c b/block/win32-aio.c index 2d509a9a7b..95e3ab1541 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -27,7 +27,7 @@ #include "block/block_int.h" #include "qemu/module.h" #include "block/aio.h" -#include "raw-aio.h" +#include "block/raw-aio.h" #include "qemu/event_notifier.h" #include "qemu/iov.h" #include <windows.h> diff --git a/bsd-user/main.c b/bsd-user/main.c index 4819b9ec63..315ba1d10c 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=]<pattern>][,events=<file>][,file=<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)); @@ -1116,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/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, _("<illegal precision>")); + func (stream, "<illegal precision>"); 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 _("<internal disassembler error>") +#define INTERNAL_DISASSEMBLER_ERROR "<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, _("<function code %d>"), fc); + (*info->fprintf_func) (info->stream, "<function code %d>", fc); } break; @@ -1827,7 +1827,7 @@ match_insn_m68k (bfd_vma memaddr, { info->fprintf_func (info->stream, /* xgettext:c-format */ - _("<internal error in opcode table: %s %s>\n"), + "<internal error in opcode table: %s %s>\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/docs/specs/parallels.txt b/docs/specs/parallels.txt index b4fe2295fb..e9271eba5d 100644 --- a/docs/specs/parallels.txt +++ b/docs/specs/parallels.txt @@ -94,7 +94,7 @@ Bytes: Bit 0: Empty Image bit. If set, the image should be considered clear. - Bits 2-31: Unused. + Bits 1-31: Unused. 56 - 63: ext_off Format Extension offset, an offset, in sectors, from the start of diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 7da9e6cb91..74446c669e 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?,vcpu:i?", + .params = "[name] [vcpu]", + .help = "show available trace-events & their state " + "(name: event name pattern; vcpu: vCPU to query, default is any)", .mhandler.cmd = hmp_info_trace_events, + .command_completion = info_trace_events_completion, }, STEXI 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, }, @@ -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/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 54b9ac1da6..704a763603 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -112,10 +112,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, s->vdev = vdev; s->conf = conf; - if (conf->iothread) { - s->iothread = conf->iothread; - object_ref(OBJECT(s->iothread)); - } + s->iothread = conf->iothread; + object_ref(OBJECT(s->iothread)); s->ctx = iothread_get_aio_context(s->iothread); s->bh = aio_bh_new(s->ctx, notify_guest_bh, s); s->batch_notify_vqs = bitmap_new(conf->num_queues); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 44783c50ab..c8436a19d6 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1828,6 +1828,7 @@ static int vfio_add_ext_cap(VFIOPCIDevice *vdev) switch (cap_id) { case PCI_EXT_CAP_ID_SRIOV: /* Read-only VF BARs confuse OVMF */ + case PCI_EXT_CAP_ID_ARI: /* XXX Needs next function virtualization */ trace_vfio_add_ext_cap_dropped(vdev->vbasedev.name, cap_id, next); break; default: diff --git a/include/block/aio.h b/include/block/aio.h index 88a64eeb3c..209551deb2 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -47,6 +47,9 @@ typedef struct AioHandler AioHandler; typedef void QEMUBHFunc(void *opaque); typedef void IOHandler(void *opaque); +struct ThreadPool; +struct LinuxAioState; + struct AioContext { GSource source; @@ -119,6 +122,13 @@ struct AioContext { /* Thread pool for performing work and receiving completion callbacks */ struct ThreadPool *thread_pool; +#ifdef CONFIG_LINUX_AIO + /* State for native Linux AIO. Uses aio_context_acquire/release for + * locking. + */ + struct LinuxAioState *linux_aio; +#endif + /* TimerLists for calling timers - one per clock type */ QEMUTimerListGroup tlg; @@ -335,6 +345,9 @@ GSource *aio_get_g_source(AioContext *ctx); /* Return the ThreadPool bound to this AioContext */ struct ThreadPool *aio_get_thread_pool(AioContext *ctx); +/* Return the LinuxAioState bound to this AioContext */ +struct LinuxAioState *aio_get_linux_aio(AioContext *ctx); + /** * aio_timer_new: * @ctx: the aio context @@ -439,6 +452,6 @@ static inline bool aio_node_check(AioContext *ctx, bool is_external) * * Initialize the aio context. */ -void aio_context_setup(AioContext *ctx, Error **errp); +void aio_context_setup(AioContext *ctx); #endif diff --git a/block/raw-aio.h b/include/block/raw-aio.h index a4cdbbf1b7..a4cdbbf1b7 100644 --- a/block/raw-aio.h +++ b/include/block/raw-aio.h 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 */ 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 617a179f14..462e820469 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=]<pattern>][,events=<file>][,file=<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)); @@ -4791,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; @@ -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); } @@ -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) { - 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; + 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) { 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) { size_t len; 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 <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. # 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" } } @@ -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/scripts/checkpatch.pl b/scripts/checkpatch.pl index cf32c8f5fa..afa7f79f83 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1279,6 +1279,11 @@ sub process { } } +# Accept git diff extended headers as valid patches + if ($line =~ /^(?:rename|copy) (?:from|to) [\w\/\.\-]+\s*$/) { + $is_patch = 1; + } + #check the patch for a signoff: if ($line =~ /^\s*signed-off-by:/i) { # This is a signoff, if ugly, so do not double report. 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 <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" __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 <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" __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 <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" __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/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 <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" __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/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) 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 <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(); +} 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 deacc8f894..a4e5f4aa06 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 <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. * See the COPYING file in the top-level directory. @@ -10,8 +10,13 @@ #ifndef TRACE__CONTROL_INTERNAL_H #define TRACE__CONTROL_INTERNAL_H +#include <stddef.h> /* 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; @@ -38,6 +43,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); @@ -50,24 +65,38 @@ 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); } -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 <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]--; + } + } +} 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 <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. * 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 452a800eb2..0413b28769 100644 --- a/trace/control.h +++ b/trace/control.h @@ -86,6 +86,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: * * Get the name of an event. @@ -107,6 +124,23 @@ static const char * trace_event_get_name(TraceEvent *ev); ((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. * @@ -121,10 +155,19 @@ 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: * * Set the tracing state of an event (only if possible). @@ -138,13 +181,38 @@ 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); @@ -201,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/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 <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. * 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; diff --git a/trace/qmp.c b/trace/qmp.c index 8aa2660aac..11d2564e7b 100644 --- a/trace/qmp.c +++ b/trace/qmp.c @@ -1,7 +1,7 @@ /* * QMP commands for tracing events. * - * Copyright (C) 2014 Lluís Vilanova <vilanova@ac.upc.edu> + * Copyright (C) 2014-2016 Lluís Vilanova <vilanova@ac.upc.edu> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -12,63 +12,153 @@ #include "trace/control.h" -TraceEventInfoList *qmp_trace_event_get_state(const char *name, Error **errp) +static CPUState *get_cpu(bool has_vcpu, int vcpu, Error **errp) { + if (has_vcpu) { + CPUState *cpu = qemu_get_cpu(vcpu); + if (cpu == NULL) { + error_setg(errp, "invalid vCPU index %u", vcpu); + } + return cpu; + } else { + return NULL; + } +} + +static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern, + const char *name, Error **errp) +{ + if (!is_pattern) { + TraceEvent *ev = trace_event_name(name); + + /* error for non-existing event */ + if (ev == NULL) { + error_setg(errp, "unknown event \"%s\"", name); + return false; + } + + /* error for non-vcpu event */ + if (has_vcpu && !trace_event_is_vcpu(ev)) { + error_setg(errp, "event \"%s\" is not vCPU-specific", name); + return false; + } + + /* error for unavailable event */ + if (!ignore_unavailable && !trace_event_get_state_static(ev)) { + error_setg(errp, "event \"%s\" is disabled", name); + return false; + } + + return true; + } else { + /* error for unavailable events */ + TraceEvent *ev = NULL; + while ((ev = trace_event_pattern(name, ev)) != NULL) { + if (!ignore_unavailable && !trace_event_get_state_static(ev)) { + error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev)); + return false; + } + } + return true; + } +} + +TraceEventInfoList *qmp_trace_event_get_state(const char *name, + bool has_vcpu, int64_t vcpu, + Error **errp) +{ + Error *err = NULL; TraceEventInfoList *events = NULL; - bool found = false; TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(name); + CPUState *cpu; + /* Check provided vcpu */ + cpu = get_cpu(has_vcpu, vcpu, &err); + if (err) { + error_propagate(errp, err); + return NULL; + } + + /* Check events */ + if (!check_events(has_vcpu, true, is_pattern, name, errp)) { + return NULL; + } + + /* Get states (all errors checked above) */ ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - TraceEventInfoList *elem = g_new(TraceEventInfoList, 1); + TraceEventInfoList *elem; + bool is_vcpu = trace_event_is_vcpu(ev); + if (has_vcpu && !is_vcpu) { + continue; + } + + elem = g_new(TraceEventInfoList, 1); elem->value = g_new(TraceEventInfo, 1); + elem->value->vcpu = is_vcpu; elem->value->name = g_strdup(trace_event_get_name(ev)); + if (!trace_event_get_state_static(ev)) { elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE; - } else if (!trace_event_get_state_dynamic(ev)) { - elem->value->state = TRACE_EVENT_STATE_DISABLED; } else { - elem->value->state = TRACE_EVENT_STATE_ENABLED; + if (has_vcpu) { + if (is_vcpu) { + if (trace_event_get_vcpu_state_dynamic(cpu, ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } + /* else: already skipped above */ + } else { + if (trace_event_get_state_dynamic(ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } } elem->next = events; events = elem; - found = true; - } - - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); } return events; } void qmp_trace_event_set_state(const char *name, bool enable, - bool has_ignore_unavailable, - bool ignore_unavailable, Error **errp) + bool has_ignore_unavailable, bool ignore_unavailable, + bool has_vcpu, int64_t vcpu, + Error **errp) { - bool found = false; + Error *err = NULL; TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(name); + CPUState *cpu; - /* Check all selected events are dynamic */ - ev = NULL; - while ((ev = trace_event_pattern(name, ev)) != NULL) { - found = true; - if (!(has_ignore_unavailable && ignore_unavailable) && - !trace_event_get_state_static(ev)) { - error_setg(errp, "cannot set dynamic tracing state for \"%s\"", - trace_event_get_name(ev)); - return; - } + /* Check provided vcpu */ + cpu = get_cpu(has_vcpu, vcpu, &err); + if (err) { + error_propagate(errp, err); + return; } - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); + + /* Check events */ + if (!check_events(has_vcpu, has_ignore_unavailable && ignore_unavailable, + is_pattern, name, errp)) { return; } - /* Apply changes */ + /* Apply changes (all errors checked above) */ ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - if (trace_event_get_state_static(ev)) { + if (!trace_event_get_state_static(ev) || + (has_vcpu && !trace_event_is_vcpu(ev))) { + continue; + } + if (has_vcpu) { + trace_event_set_vcpu_state_dynamic(cpu, ev, enable); + } else { trace_event_set_state_dynamic(ev, enable); } } 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, @@ -4598,6 +4598,7 @@ int main(int argc, char **argv, char **envp) os_setup_post(); + trace_init_vcpu_events(); main_loop(); replay_disable_events(); |