/* TODO: this is pretty bad: we get a cache line bounce * for the wait queue on poll and another one on read, * plus the read which is there just to clear the
* current state. */ staticvoid wait_for_interrupt(struct vdev_info *dev)
{ int i; unsignedlonglong val;
poll(dev->fds, dev->nvqs, -1); for (i = 0; i < dev->nvqs; ++i) if (dev->fds[i].revents & POLLIN) {
read(dev->fds[i].fd, &val, sizeof val);
}
}
staticvoid run_test(struct vdev_info *dev, struct vq_info *vq, bool delayed, int batch, int reset_n, int bufs)
{ struct scatterlist sl; long started = 0, completed = 0, next_reset = reset_n; long completed_before, started_before; int r, test = 1; unsignedint len; longlong spurious = 0; constbool random_batch = batch == RANDOM_BATCH;
r = ioctl(dev->control, VHOST_TEST_RUN, &test);
assert(r >= 0); if (!reset_n) {
next_reset = INT_MAX;
}
for (;;) {
virtqueue_disable_cb(vq->vq);
completed_before = completed;
started_before = started; do { constbool reset = completed > next_reset; if (random_batch)
batch = (random() % vq->vring.num) + 1;
while (started < bufs &&
(started - completed) < batch) {
sg_init_one(&sl, dev->buf, dev->buf_size);
r = virtqueue_add_outbuf(vq->vq, &sl, 1,
dev->buf + started,
GFP_ATOMIC); if (unlikely(r != 0)) { if (r == -ENOSPC &&
started > started_before)
r = 0; else
r = -1; break;
}
++started;
if (unlikely(!virtqueue_kick(vq->vq))) {
r = -1; break;
}
}
if (started >= bufs)
r = -1;
if (reset) {
r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
&no_backend);
assert(!r);
}
/* Flush out completed bufs if any */ while (virtqueue_get_buf(vq->vq, &len)) {
++completed;
r = 0;
}
if (reset) { struct vhost_vring_state s = { .index = 0 };
vq_reset(vq, vq->vring.num, &dev->vdev);
r = ioctl(dev->control, VHOST_GET_VRING_BASE,
&s);
assert(!r);
s.num = 0;
r = ioctl(dev->control, VHOST_SET_VRING_BASE,
&null_state);
assert(!r);
r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
&backend);
assert(!r);
started = completed; while (completed > next_reset)
next_reset += completed;
}
} while (r == 0); if (completed == completed_before && started == started_before)
++spurious;
assert(completed <= bufs);
assert(started <= bufs); if (completed == bufs) break; if (delayed) { if (virtqueue_enable_cb_delayed(vq->vq))
wait_for_interrupt(dev);
} else { if (virtqueue_enable_cb(vq->vq))
wait_for_interrupt(dev);
}
}
test = 0;
r = ioctl(dev->control, VHOST_TEST_RUN, &test);
assert(r >= 0);
fprintf(stderr, "spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
spurious, started, completed);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.