Skip to content

Commit

Permalink
Fix IO performance regression in sparc
Browse files Browse the repository at this point in the history
Replace signalfd with signal handler/pipe.  There is no way to interrupt
the CPU execution loop when a file descriptor becomes readable.  This
results in a large performance regression in sparc emulation during
bootup.
   
This patch switches us to signal handler/pipe which was originally
suggested by Ian Jackson.  The signal handler lets us interrupt the
CPU emulation loop while the write to a pipe lets us avoid the
select/signal race condition.
    
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5451 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
aliguori committed Oct 8, 2008
1 parent 235262c commit 9e472e1
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 233 deletions.
4 changes: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ else
BLOCK_OBJS += block-raw-posix.o
endif

ifdef CONFIG_AIO
BLOCK_OBJS += compatfd.o
endif

######################################################################
# libqemu_common.a: Target independent part of system emulation. The
# long term path is to suppress *all* target specific code in case of
Expand Down
4 changes: 0 additions & 4 deletions Makefile.target
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,6 @@ else
OBJS+=block-raw-posix.o
endif

ifdef CONFIG_AIO
OBJS+=compatfd.o
endif

LIBS+=-lz
ifdef CONFIG_ALSA
LIBS += -lasound
Expand Down
70 changes: 35 additions & 35 deletions block-raw-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "qemu-timer.h"
#include "qemu-char.h"
#include "block_int.h"
#include "compatfd.h"
#include <assert.h>
#ifdef CONFIG_AIO
#include <aio.h>
Expand Down Expand Up @@ -453,7 +452,7 @@ typedef struct RawAIOCB {

typedef struct PosixAioState
{
int fd;
int rfd, wfd;
RawAIOCB *first_aio;
} PosixAioState;

Expand Down Expand Up @@ -494,30 +493,17 @@ static void posix_aio_read(void *opaque)
PosixAioState *s = opaque;
RawAIOCB *acb, **pacb;
int ret;
size_t offset;
union {
struct qemu_signalfd_siginfo siginfo;
char buf[128];
} sig;

/* try to read from signalfd, don't freak out if we can't read anything */
offset = 0;
while (offset < 128) {
ssize_t len;

len = read(s->fd, sig.buf + offset, 128 - offset);
ssize_t len;

do {
char byte;

len = read(s->rfd, &byte, 1);
if (len == -1 && errno == EINTR)
continue;
if (len == -1 && errno == EAGAIN) {
/* there is no natural reason for this to happen,
* so we'll spin hard until we get everything just
* to be on the safe side. */
if (offset > 0)
continue;
}

offset += len;
}
if (len == -1 && errno == EAGAIN)
break;
} while (len == -1);

for(;;) {
pacb = &s->first_aio;
Expand Down Expand Up @@ -565,10 +551,22 @@ static int posix_aio_flush(void *opaque)

static PosixAioState *posix_aio_state;

static void aio_signal_handler(int signum)
{
if (posix_aio_state) {
char byte = 0;

write(posix_aio_state->wfd, &byte, sizeof(byte));
}

qemu_service_io();
}

static int posix_aio_init(void)
{
sigset_t mask;
struct sigaction act;
PosixAioState *s;
int fds[2];

if (posix_aio_state)
return 0;
Expand All @@ -577,21 +575,23 @@ static int posix_aio_init(void)
if (s == NULL)
return -ENOMEM;

/* Make sure to block AIO signal */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
sigfillset(&act.sa_mask);
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
act.sa_handler = aio_signal_handler;
sigaction(SIGUSR2, &act, NULL);

s->first_aio = NULL;
s->fd = qemu_signalfd(&mask);
if (s->fd == -1) {
fprintf(stderr, "failed to create signalfd\n");
if (pipe(fds) == -1) {
fprintf(stderr, "failed to create pipe\n");
return -errno;
}

fcntl(s->fd, F_SETFL, O_NONBLOCK);
s->rfd = fds[0];
s->wfd = fds[1];

fcntl(s->wfd, F_SETFL, O_NONBLOCK);

qemu_aio_set_fd_handler(s->fd, posix_aio_read, NULL, posix_aio_flush, s);
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);

#if defined(__linux__)
{
Expand Down
127 changes: 0 additions & 127 deletions compatfd.c

This file was deleted.

28 changes: 0 additions & 28 deletions compatfd.h

This file was deleted.

35 changes: 0 additions & 35 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ aio="yes"
nptl="yes"
mixemu="no"
bluez="yes"
signalfd="no"
eventfd="no"

# OS specific
targetos=`uname -s`
Expand Down Expand Up @@ -930,33 +928,6 @@ EOF
fi
fi

##########################################
# signalfd probe
cat > $TMPC << EOF
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
EOF

if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
signalfd=yes
fi

##########################################
# eventfd probe
cat > $TMPC << EOF
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
int main(void) { return syscall(SYS_eventfd, 0); }
EOF

if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
eventfd=yes
fi

# Check if tools are available to build documentation.
if [ -x "`which texi2html 2>/dev/null`" ] && \
[ -x "`which pod2man 2>/dev/null`" ]; then
Expand Down Expand Up @@ -1297,12 +1268,6 @@ if test "$aio" = "yes" ; then
echo "#define CONFIG_AIO 1" >> $config_h
echo "CONFIG_AIO=yes" >> $config_mak
fi
if test "$signalfd" = "yes" ; then
echo "#define CONFIG_signalfd 1" >> $config_h
fi
if test "$eventfd" = "yes" ; then
echo "#define CONFIG_eventfd 1" >> $config_h
fi

# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
Expand Down
3 changes: 3 additions & 0 deletions qemu-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,7 @@ struct pcmcia_card_s;
void cpu_save(QEMUFile *f, void *opaque);
int cpu_load(QEMUFile *f, void *opaque, int version_id);

/* Force QEMU to stop what it's doing and service IO */
void qemu_service_io(void);

#endif
4 changes: 4 additions & 0 deletions qemu-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ struct QEMUBH
void *opaque;
};

void qemu_service_io(void)
{
}

void term_printf(const char *fmt, ...)
{
}
Expand Down
13 changes: 13 additions & 0 deletions vl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7475,6 +7475,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}

void qemu_service_io(void)
{
CPUState *env = cpu_single_env;
if (env) {
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
#ifdef USE_KQEMU
if (env->kqemu_enabled) {
kqemu_cpu_interrupt(env);
}
#endif
}
}

/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */

Expand Down

0 comments on commit 9e472e1

Please sign in to comment.