Commit 9e472e101f37233f4e32d181d2fee29014c1cf2f

Authored by aliguori
1 parent 235262cf

Fix IO performance regression in sparc

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
Makefile
@@ -59,10 +59,6 @@ else @@ -59,10 +59,6 @@ else
59 BLOCK_OBJS += block-raw-posix.o 59 BLOCK_OBJS += block-raw-posix.o
60 endif 60 endif
61 61
62 -ifdef CONFIG_AIO  
63 -BLOCK_OBJS += compatfd.o  
64 -endif  
65 -  
66 ###################################################################### 62 ######################################################################
67 # libqemu_common.a: Target independent part of system emulation. The 63 # libqemu_common.a: Target independent part of system emulation. The
68 # long term path is to suppress *all* target specific code in case of 64 # long term path is to suppress *all* target specific code in case of
Makefile.target
@@ -481,10 +481,6 @@ else @@ -481,10 +481,6 @@ else
481 OBJS+=block-raw-posix.o 481 OBJS+=block-raw-posix.o
482 endif 482 endif
483 483
484 -ifdef CONFIG_AIO  
485 -OBJS+=compatfd.o  
486 -endif  
487 -  
488 LIBS+=-lz 484 LIBS+=-lz
489 ifdef CONFIG_ALSA 485 ifdef CONFIG_ALSA
490 LIBS += -lasound 486 LIBS += -lasound
block-raw-posix.c
@@ -25,7 +25,6 @@ @@ -25,7 +25,6 @@
25 #include "qemu-timer.h" 25 #include "qemu-timer.h"
26 #include "qemu-char.h" 26 #include "qemu-char.h"
27 #include "block_int.h" 27 #include "block_int.h"
28 -#include "compatfd.h"  
29 #include <assert.h> 28 #include <assert.h>
30 #ifdef CONFIG_AIO 29 #ifdef CONFIG_AIO
31 #include <aio.h> 30 #include <aio.h>
@@ -453,7 +452,7 @@ typedef struct RawAIOCB { @@ -453,7 +452,7 @@ typedef struct RawAIOCB {
453 452
454 typedef struct PosixAioState 453 typedef struct PosixAioState
455 { 454 {
456 - int fd; 455 + int rfd, wfd;
457 RawAIOCB *first_aio; 456 RawAIOCB *first_aio;
458 } PosixAioState; 457 } PosixAioState;
459 458
@@ -494,30 +493,17 @@ static void posix_aio_read(void *opaque) @@ -494,30 +493,17 @@ static void posix_aio_read(void *opaque)
494 PosixAioState *s = opaque; 493 PosixAioState *s = opaque;
495 RawAIOCB *acb, **pacb; 494 RawAIOCB *acb, **pacb;
496 int ret; 495 int ret;
497 - size_t offset;  
498 - union {  
499 - struct qemu_signalfd_siginfo siginfo;  
500 - char buf[128];  
501 - } sig;  
502 -  
503 - /* try to read from signalfd, don't freak out if we can't read anything */  
504 - offset = 0;  
505 - while (offset < 128) {  
506 - ssize_t len;  
507 -  
508 - len = read(s->fd, sig.buf + offset, 128 - offset); 496 + ssize_t len;
  497 +
  498 + do {
  499 + char byte;
  500 +
  501 + len = read(s->rfd, &byte, 1);
509 if (len == -1 && errno == EINTR) 502 if (len == -1 && errno == EINTR)
510 continue; 503 continue;
511 - if (len == -1 && errno == EAGAIN) {  
512 - /* there is no natural reason for this to happen,  
513 - * so we'll spin hard until we get everything just  
514 - * to be on the safe side. */  
515 - if (offset > 0)  
516 - continue;  
517 - }  
518 -  
519 - offset += len;  
520 - } 504 + if (len == -1 && errno == EAGAIN)
  505 + break;
  506 + } while (len == -1);
521 507
522 for(;;) { 508 for(;;) {
523 pacb = &s->first_aio; 509 pacb = &s->first_aio;
@@ -565,10 +551,22 @@ static int posix_aio_flush(void *opaque) @@ -565,10 +551,22 @@ static int posix_aio_flush(void *opaque)
565 551
566 static PosixAioState *posix_aio_state; 552 static PosixAioState *posix_aio_state;
567 553
  554 +static void aio_signal_handler(int signum)
  555 +{
  556 + if (posix_aio_state) {
  557 + char byte = 0;
  558 +
  559 + write(posix_aio_state->wfd, &byte, sizeof(byte));
  560 + }
  561 +
  562 + qemu_service_io();
  563 +}
  564 +
568 static int posix_aio_init(void) 565 static int posix_aio_init(void)
569 { 566 {
570 - sigset_t mask; 567 + struct sigaction act;
571 PosixAioState *s; 568 PosixAioState *s;
  569 + int fds[2];
572 570
573 if (posix_aio_state) 571 if (posix_aio_state)
574 return 0; 572 return 0;
@@ -577,21 +575,23 @@ static int posix_aio_init(void) @@ -577,21 +575,23 @@ static int posix_aio_init(void)
577 if (s == NULL) 575 if (s == NULL)
578 return -ENOMEM; 576 return -ENOMEM;
579 577
580 - /* Make sure to block AIO signal */  
581 - sigemptyset(&mask);  
582 - sigaddset(&mask, SIGUSR2);  
583 - sigprocmask(SIG_BLOCK, &mask, NULL);  
584 - 578 + sigfillset(&act.sa_mask);
  579 + act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
  580 + act.sa_handler = aio_signal_handler;
  581 + sigaction(SIGUSR2, &act, NULL);
  582 +
585 s->first_aio = NULL; 583 s->first_aio = NULL;
586 - s->fd = qemu_signalfd(&mask);  
587 - if (s->fd == -1) {  
588 - fprintf(stderr, "failed to create signalfd\n"); 584 + if (pipe(fds) == -1) {
  585 + fprintf(stderr, "failed to create pipe\n");
589 return -errno; 586 return -errno;
590 } 587 }
591 588
592 - fcntl(s->fd, F_SETFL, O_NONBLOCK); 589 + s->rfd = fds[0];
  590 + s->wfd = fds[1];
  591 +
  592 + fcntl(s->wfd, F_SETFL, O_NONBLOCK);
593 593
594 - qemu_aio_set_fd_handler(s->fd, posix_aio_read, NULL, posix_aio_flush, s); 594 + qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
595 595
596 #if defined(__linux__) 596 #if defined(__linux__)
597 { 597 {
compatfd.c deleted 100644 โ†’ 0
1 -/*  
2 - * signalfd/eventfd compatibility  
3 - *  
4 - * Copyright IBM, Corp. 2008  
5 - *  
6 - * Authors:  
7 - * Anthony Liguori <aliguori@us.ibm.com>  
8 - *  
9 - * This work is licensed under the terms of the GNU GPL, version 2. See  
10 - * the COPYING file in the top-level directory.  
11 - *  
12 - */  
13 -  
14 -#include "qemu-common.h"  
15 -#include "compatfd.h"  
16 -  
17 -#include <sys/syscall.h>  
18 -#include <pthread.h>  
19 -  
20 -struct sigfd_compat_info  
21 -{  
22 - sigset_t mask;  
23 - int fd;  
24 -};  
25 -  
26 -static void *sigwait_compat(void *opaque)  
27 -{  
28 - struct sigfd_compat_info *info = opaque;  
29 - int err;  
30 - sigset_t all;  
31 -  
32 - sigfillset(&all);  
33 - sigprocmask(SIG_BLOCK, &all, NULL);  
34 -  
35 - do {  
36 - siginfo_t siginfo;  
37 -  
38 - err = sigwaitinfo(&info->mask, &siginfo);  
39 - if (err == -1 && errno == EINTR) {  
40 - err = 0;  
41 - continue;  
42 - }  
43 -  
44 - if (err > 0) {  
45 - char buffer[128];  
46 - size_t offset = 0;  
47 -  
48 - memcpy(buffer, &err, sizeof(err));  
49 - while (offset < sizeof(buffer)) {  
50 - ssize_t len;  
51 -  
52 - len = write(info->fd, buffer + offset,  
53 - sizeof(buffer) - offset);  
54 - if (len == -1 && errno == EINTR)  
55 - continue;  
56 -  
57 - if (len <= 0) {  
58 - err = -1;  
59 - break;  
60 - }  
61 -  
62 - offset += len;  
63 - }  
64 - }  
65 - } while (err >= 0);  
66 -  
67 - return NULL;  
68 -}  
69 -  
70 -static int qemu_signalfd_compat(const sigset_t *mask)  
71 -{  
72 - pthread_attr_t attr;  
73 - pthread_t tid;  
74 - struct sigfd_compat_info *info;  
75 - int fds[2];  
76 -  
77 - info = malloc(sizeof(*info));  
78 - if (info == NULL) {  
79 - errno = ENOMEM;  
80 - return -1;  
81 - }  
82 -  
83 - if (pipe(fds) == -1) {  
84 - free(info);  
85 - return -1;  
86 - }  
87 -  
88 - memcpy(&info->mask, mask, sizeof(*mask));  
89 - info->fd = fds[1];  
90 -  
91 - pthread_attr_init(&attr);  
92 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  
93 -  
94 - pthread_create(&tid, &attr, sigwait_compat, info);  
95 -  
96 - pthread_attr_destroy(&attr);  
97 -  
98 - return fds[0];  
99 -}  
100 -  
101 -int qemu_signalfd(const sigset_t *mask)  
102 -{  
103 -#if defined(CONFIG_signalfd)  
104 - int ret;  
105 -  
106 - ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);  
107 - if (ret != -1)  
108 - return ret;  
109 -#endif  
110 -  
111 - return qemu_signalfd_compat(mask);  
112 -}  
113 -  
114 -int qemu_eventfd(int *fds)  
115 -{  
116 -#if defined(CONFIG_eventfd)  
117 - int ret;  
118 -  
119 - ret = syscall(SYS_eventfd, 0);  
120 - if (ret >= 0) {  
121 - fds[0] = fds[1] = ret;  
122 - return 0;  
123 - }  
124 -#endif  
125 -  
126 - return pipe(fds);  
127 -}  
compatfd.h deleted 100644 โ†’ 0
1 -/*  
2 - * signalfd/eventfd compatibility  
3 - *  
4 - * Copyright IBM, Corp. 2008  
5 - *  
6 - * Authors:  
7 - * Anthony Liguori <aliguori@us.ibm.com>  
8 - *  
9 - * This work is licensed under the terms of the GNU GPL, version 2. See  
10 - * the COPYING file in the top-level directory.  
11 - *  
12 - */  
13 -  
14 -#ifndef QEMU_COMPATFD_H  
15 -#define QEMU_COMPATFD_H  
16 -  
17 -#include <signal.h>  
18 -  
19 -struct qemu_signalfd_siginfo {  
20 - uint32_t ssi_signo;  
21 - uint8_t pad[124];  
22 -};  
23 -  
24 -int qemu_signalfd(const sigset_t *mask);  
25 -  
26 -int qemu_eventfd(int *fds);  
27 -  
28 -#endif  
configure
@@ -113,8 +113,6 @@ aio=&quot;yes&quot; @@ -113,8 +113,6 @@ aio=&quot;yes&quot;
113 nptl="yes" 113 nptl="yes"
114 mixemu="no" 114 mixemu="no"
115 bluez="yes" 115 bluez="yes"
116 -signalfd="no"  
117 -eventfd="no"  
118 116
119 # OS specific 117 # OS specific
120 targetos=`uname -s` 118 targetos=`uname -s`
@@ -930,33 +928,6 @@ EOF @@ -930,33 +928,6 @@ EOF
930 fi 928 fi
931 fi 929 fi
932 930
933 -##########################################  
934 -# signalfd probe  
935 -cat > $TMPC << EOF  
936 -#define _GNU_SOURCE  
937 -#include <unistd.h>  
938 -#include <sys/syscall.h>  
939 -#include <signal.h>  
940 -int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }  
941 -EOF  
942 -  
943 -if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then  
944 - signalfd=yes  
945 -fi  
946 -  
947 -##########################################  
948 -# eventfd probe  
949 -cat > $TMPC << EOF  
950 -#define _GNU_SOURCE  
951 -#include <unistd.h>  
952 -#include <sys/syscall.h>  
953 -int main(void) { return syscall(SYS_eventfd, 0); }  
954 -EOF  
955 -  
956 -if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then  
957 - eventfd=yes  
958 -fi  
959 -  
960 # Check if tools are available to build documentation. 931 # Check if tools are available to build documentation.
961 if [ -x "`which texi2html 2>/dev/null`" ] && \ 932 if [ -x "`which texi2html 2>/dev/null`" ] && \
962 [ -x "`which pod2man 2>/dev/null`" ]; then 933 [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -1297,12 +1268,6 @@ if test &quot;$aio&quot; = &quot;yes&quot; ; then @@ -1297,12 +1268,6 @@ if test &quot;$aio&quot; = &quot;yes&quot; ; then
1297 echo "#define CONFIG_AIO 1" >> $config_h 1268 echo "#define CONFIG_AIO 1" >> $config_h
1298 echo "CONFIG_AIO=yes" >> $config_mak 1269 echo "CONFIG_AIO=yes" >> $config_mak
1299 fi 1270 fi
1300 -if test "$signalfd" = "yes" ; then  
1301 - echo "#define CONFIG_signalfd 1" >> $config_h  
1302 -fi  
1303 -if test "$eventfd" = "yes" ; then  
1304 - echo "#define CONFIG_eventfd 1" >> $config_h  
1305 -fi  
1306 1271
1307 # XXX: suppress that 1272 # XXX: suppress that
1308 if [ "$bsd" = "yes" ] ; then 1273 if [ "$bsd" = "yes" ] ; then
qemu-common.h
@@ -139,4 +139,7 @@ struct pcmcia_card_s; @@ -139,4 +139,7 @@ struct pcmcia_card_s;
139 void cpu_save(QEMUFile *f, void *opaque); 139 void cpu_save(QEMUFile *f, void *opaque);
140 int cpu_load(QEMUFile *f, void *opaque, int version_id); 140 int cpu_load(QEMUFile *f, void *opaque, int version_id);
141 141
  142 +/* Force QEMU to stop what it's doing and service IO */
  143 +void qemu_service_io(void);
  144 +
142 #endif 145 #endif
qemu-tool.c
@@ -26,6 +26,10 @@ struct QEMUBH @@ -26,6 +26,10 @@ struct QEMUBH
26 void *opaque; 26 void *opaque;
27 }; 27 };
28 28
  29 +void qemu_service_io(void)
  30 +{
  31 +}
  32 +
29 void term_printf(const char *fmt, ...) 33 void term_printf(const char *fmt, ...)
30 { 34 {
31 } 35 }
@@ -7475,6 +7475,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) @@ -7475,6 +7475,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
7475 return 0; 7475 return 0;
7476 } 7476 }
7477 7477
  7478 +void qemu_service_io(void)
  7479 +{
  7480 + CPUState *env = cpu_single_env;
  7481 + if (env) {
  7482 + cpu_interrupt(env, CPU_INTERRUPT_EXIT);
  7483 +#ifdef USE_KQEMU
  7484 + if (env->kqemu_enabled) {
  7485 + kqemu_cpu_interrupt(env);
  7486 + }
  7487 +#endif
  7488 + }
  7489 +}
  7490 +
7478 /***********************************************************/ 7491 /***********************************************************/
7479 /* bottom halves (can be seen as timers which expire ASAP) */ 7492 /* bottom halves (can be seen as timers which expire ASAP) */
7480 7493