[Pkg-uml-pkgs] Bug#628105: uml-utilities: uml-switch eats way more CPU than it should

Anton Ivanov arivanov at sigsegv.cx
Fri May 27 10:11:00 UTC 2011


Package: uml-utilities
Version: 20070815-1.1
Severity: normal
Tags: patch


UML Switch eats about as much CPU as the VM itself (if not more).

I read the source and noticed that it uses poll() instead of epoll()
in the main loop.

Attached is a diff for an epoll based version. It uses approximately 
1/4 of the CPU used by the poll() based one in my test case.

I have tested the basic functionality - VM attach/VM detach, etc. All
seems to work.


*** uml_switch.c.orig	2006-02-27 21:02:36.000000000 +0000
--- uml_switch.c	2011-05-27 11:05:36.000000000 +0100
***************
*** 10,16 ****
  #include <stdint.h>
  #include <sys/socket.h>
  #include <sys/un.h>
! #include <sys/poll.h>
  #include <sys/time.h>
  #include <unistd.h>
  #include "switch.h"
--- 10,16 ----
  #include <stdint.h>
  #include <sys/socket.h>
  #include <sys/un.h>
! #include <sys/epoll.h>
  #include <sys/time.h>
  #include <unistd.h>
  #include "switch.h"
***************
*** 27,32 ****
--- 27,37 ----
  static int hub = 0;
  static int compat_v0 = 0;
  
+ // EPOLL FD
+ 
+ static int epfd;
+ #define MAX_EVENTS   128
+ 
  enum request_type { REQ_NEW_CONTROL };
  
  struct request_v0 {
***************
*** 99,133 ****
  static int maxfds = 0;
  static int nfds = 0;
  
  static void add_fd(int fd)
  {
!   struct pollfd *p;
  
!   if(nfds == maxfds){
!     maxfds = maxfds ? 2 * maxfds : 4;
!     if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
!       perror("realloc");
!       cleanup();
!       exit(1);
!     }
!   }
!   p = &fds[nfds++];
!   p->fd = fd;
!   p->events = POLLIN;
! }
  
  static void remove_fd(int fd)
  {
!   int i;
  
!   for(i = 0; i < nfds; i++){
!     if(fds[i].fd == fd) break;
!   }
!   if(i == nfds){
!     fprintf(stderr, "remove_fd : Couldn't find descriptor %d\n", fd);
!   }
!   memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
!   nfds--;
  }
  
  static void sig_handler(int sig)
--- 104,161 ----
  static int maxfds = 0;
  static int nfds = 0;
  
+ //static void add_fd(int fd)
+ //{
+ //  struct pollfd *p;
+ //
+ //  if(nfds == maxfds){
+ //    maxfds = maxfds ? 2 * maxfds : 4;
+ //    if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
+ //      perror("realloc");
+ //      cleanup();
+ //      exit(1);
+ //    }
+ //  }
+ //  p = &fds[nfds++];
+ //  p->fd = fd;
+ //  p->events = POLLIN;
+ //}
+ 
  static void add_fd(int fd)
  {
!     struct epoll_event event;
!     int ret;
  
!     event.data.fd = fd; /* return the fd to us later */
!     event.events = EPOLLIN || EPOLLOUT;
! 
!     ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &event);
!     if (ret)
! 	perror ("epoll_ctl"); 
! }
! 
! //static void remove_fd(int fd)
! //{
! //  int i;
! //
! //  for(i = 0; i < nfds; i++){
! //    if(fds[i].fd == fd) break;
! //  }
! //  if(i == nfds){
! //    fprintf(stderr, "remove_fd : Couldn't find descriptor %d\n", fd);
! //  }
! //  memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
! //  nfds--;
! //}
  
  static void remove_fd(int fd)
  {
!     struct epoll_event event;
!     int ret;
  
!     ret = epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &event);
!     if (ret)
! 	perror ("epoll_ctl"); 
  }
  
  static void sig_handler(int sig)
***************
*** 503,508 ****
--- 531,541 ----
  #endif
    printf("\n");
  
+   epfd = epoll_create (MAX_EVENTS); // need to fix magic number
+   if (epfd < 0)
+      perror ("epoll_create");
+ 
+ 
    if(isatty(0))
      add_fd(0);
    add_fd(connect_fd);
***************
*** 518,536 ****
      exit(1);
    }
  
!   while(1){
      char buf[128];
  
!     n = poll(fds, nfds, -1);
!     if(n < 0){
        if(errno == EINTR) continue;
!       perror("poll");
        break;
      }
!     for(i = 0; i < nfds; i++){
!       if(fds[i].revents == 0) continue;
!       if(fds[i].fd == 0){
! 	if(fds[i].revents & POLLHUP){
  	  printf("EOF on stdin, cleaning up and exiting\n");
  	  goto out;
  	}
--- 551,580 ----
      exit(1);
    }
  
!     struct epoll_event *events;
!     int nr_events;
! 
!     events = malloc (sizeof (struct epoll_event) * MAX_EVENTS);
!     if (!events) {
!           perror ("malloc");
!           return 1;
!     } 
! 
!     while(1) {
!     
      char buf[128];
  
!     nr_events = epoll_wait(epfd, events, MAX_EVENTS, -1);
! 
!     if(nr_events < 0){
        if(errno == EINTR) continue;
!       perror("epoll");
        break;
      }
!     for(i = 0; i < nr_events; i++){
!       //epoll loop
!       if(events[i].data.fd == 0){
! 	if(events[i].events & EPOLLHUP){
  	  printf("EOF on stdin, cleaning up and exiting\n");
  	  goto out;
  	}
***************
*** 545,565 ****
  	  goto out;
  	}
        }
!       else if(fds[i].fd == connect_fd){
! 	if(fds[i].revents & POLLHUP){
  	  printf("Error on connection fd\n");
  	  continue;
  	}
  	accept_connection(connect_fd);
        }
!       else if(fds[i].fd == data_fd) handle_sock_data(data_fd, hub);
  #ifdef TUNTAP
!       else if(fds[i].fd == tap_fd) handle_tap_data(tap_fd, hub);
  #endif
        else {
! 	new = handle_port(fds[i].fd);
! 	if(new) new_port(fds[i].fd, data_fd);
! 	else close_descriptor(fds[i].fd);
        }
      }
    }
--- 589,609 ----
  	  goto out;
  	}
        }
!       else if(events[i].data.fd == connect_fd){
! 	if(events[i].events & EPOLLHUP){
  	  printf("Error on connection fd\n");
  	  continue;
  	}
  	accept_connection(connect_fd);
        }
!       else if(events[i].data.fd == data_fd) handle_sock_data(data_fd, hub);
  #ifdef TUNTAP
!       else if(events[i].data.fd == tap_fd) handle_tap_data(tap_fd, hub);
  #endif
        else {
! 	new = handle_port(events[i].data.fd);
! 	if(new) new_port(events[i].data.fd, data_fd);
! 	else close_descriptor(events[i].data.fd);
        }
      }
    }

-- System Information:
Debian Release: 6.0.1
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: i386 (i686)

Kernel: Linux 2.6.32-5-686 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages uml-utilities depends on:
ii  adduser                 3.112+nmu2       add and remove users and groups
ii  libc6                   2.11.2-10        Embedded GNU C Library: Shared lib
ii  libfuse2                2.8.4-1.1        Filesystem in USErspace library
ii  libncurses5             5.7+20100313-5   shared libraries for terminal hand
ii  libreadline5            5.2-7            GNU readline and history libraries
ii  lsb-base                3.2-23.2squeeze1 Linux Standard Base 3.2 init scrip

uml-utilities recommends no packages.

Versions of packages uml-utilities suggests:
ii  user-mode-linux             2.6.32-1um-4 User-mode Linux (kernel)

-- Configuration Files:
/etc/default/uml-utilities changed [not included]

-- no debconf information





More information about the Pkg-uml-pkgs mailing list