summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--aio-posix.c3
-rw-r--r--aio-win32.c2
-rw-r--r--async.c33
-rw-r--r--block/linux-aio.c36
-rw-r--r--block/raw-posix.c119
-rw-r--r--block/raw-win32.c2
-rw-r--r--block/win32-aio.c2
-rw-r--r--bsd-user/main.c22
-rw-r--r--disas/alpha.c6
-rw-r--r--disas/arm.c2
-rw-r--r--disas/i386.c2
-rw-r--r--disas/m68k.c4
-rw-r--r--disas/mips.c50
-rw-r--r--disas/ppc.c22
-rw-r--r--disas/sparc.c6
-rw-r--r--docs/specs/parallels.txt2
-rw-r--r--hmp-commands-info.hx8
-rw-r--r--hmp-commands.hx7
-rw-r--r--hmp.h1
-rw-r--r--hw/block/dataplane/virtio-blk.c6
-rw-r--r--hw/vfio/pci.c1
-rw-r--r--include/block/aio.h15
-rw-r--r--include/block/raw-aio.h (renamed from block/raw-aio.h)0
-rw-r--r--include/disas/bfd.h1
-rw-r--r--include/qom/cpu.h6
-rw-r--r--linux-user/main.c20
-rw-r--r--monitor.c46
-rw-r--r--qapi/trace.json33
-rw-r--r--qmp-commands.hx35
-rw-r--r--qom/cpu.c1
-rwxr-xr-xscripts/checkpatch.pl5
-rw-r--r--scripts/tracetool/backend/dtrace.py4
-rw-r--r--scripts/tracetool/backend/ftrace.py20
-rw-r--r--scripts/tracetool/backend/log.py26
-rw-r--r--scripts/tracetool/backend/simple.py13
-rw-r--r--scripts/tracetool/backend/ust.py4
-rw-r--r--scripts/tracetool/format/events_c.py11
-rw-r--r--scripts/tracetool/format/events_h.py12
-rw-r--r--scripts/tracetool/format/h.py19
-rw-r--r--stubs/Makefile.objs1
-rw-r--r--stubs/trace-control.c28
-rw-r--r--trace/Makefile.objs4
-rw-r--r--trace/control-internal.h49
-rw-r--r--trace/control-target.c53
-rw-r--r--trace/control.c29
-rw-r--r--trace/control.h79
-rw-r--r--trace/event-internal.h4
-rw-r--r--trace/qmp.c148
-rw-r--r--translate-all.h3
-rw-r--r--vl.c1
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)
{
}
diff --git a/async.c b/async.c
index b4bf205a0c..3bca9b0adb 100644
--- a/async.c
+++ b/async.c
@@ -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,
},
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/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;
diff --git a/monitor.c b/monitor.c
index d0ff246a16..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);
}
@@ -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" } }
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/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,
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();