From patchwork Fri May 27 16:18:37 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sasha Levin X-Patchwork-Id: 824802 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p4RGKJ5P032188 for ; Fri, 27 May 2011 16:20:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754433Ab1E0QUP (ORCPT ); Fri, 27 May 2011 12:20:15 -0400 Received: from mail-ww0-f44.google.com ([74.125.82.44]:51264 "EHLO mail-ww0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753040Ab1E0QUO (ORCPT ); Fri, 27 May 2011 12:20:14 -0400 Received: by wwa36 with SMTP id 36so2028484wwa.1 for ; Fri, 27 May 2011 09:20:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer; bh=J7261K2IuxzLYtb72yiewD1olLl9PQXOgQ8GgqtlTCw=; b=L5I2CcIsrRNGge6XBKUxcKvPgdOzIKws2BcePhIzq2FMW3vdvTXHZMzFmPRM3GyiV5 s0tV6Eq7BkEuqhjoyDMTUblI/fIzmMIxpqCawU8/vDOP33PvwwEML/nu0SyLCtqOD/lz AWCmBwQvZuw6nfHgh/x/rDho58F5YB/lGQmtU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=Z2kh86ZQYiXc5qaOXK1bYoHGT+mf2UCcZAFD36IfuBXVOw2fc8gXJyI+N+cdCnvw7F dCB2sKw/GrTU5MQ5+M5WjsSUjoo6YqtWM77VNhMsBcPv5pwo4BHgw7ZnApV+7MKKajiI zxDI8AakNwnHHiTnqOCCljlEZR+JpNUDRTmBg= Received: by 10.216.69.196 with SMTP id n46mr2130478wed.86.1306513212878; Fri, 27 May 2011 09:20:12 -0700 (PDT) Received: from localhost.localdomain (bzq-79-176-208-154.red.bezeqint.net [79.176.208.154]) by mx.google.com with ESMTPS id w58sm1063873weq.1.2011.05.27.09.20.10 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 27 May 2011 09:20:12 -0700 (PDT) From: Sasha Levin To: penberg@kernel.org Cc: john@jfloren.net, kvm@vger.kernel.org, mingo@elte.hu, asias.hejun@gmail.com, gorcunov@gmail.com, prasadjoshi124@gmail.com, Sasha Levin Subject: [PATCH v2 1/4] kvm tools: Add ioeventfd support Date: Fri, 27 May 2011 19:18:37 +0300 Message-Id: <1306513120-28794-1-git-send-email-levinsasha928@gmail.com> X-Mailer: git-send-email 1.7.5.rc3 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 27 May 2011 16:20:20 +0000 (UTC) ioeventfd is way provided by KVM to receive notifications about reads and writes to PIO and MMIO areas within the guest. Such notifications are usefull if all we need to know is that a specific area of the memory has been changed, and we don't need a heavyweight exit to happen. The implementation uses epoll to scale to large number of ioeventfds. Benchmarks ran on a seperate (non boot) 1GB virtio-blk device, formatted as ext4, using bonnie++. cmd line: # bonnie++ -d temp/ -c 2 -s 768 -u 0 Before: Version 1.96 ------Sequential Output------ --Sequential Input- --Random- Concurrency 2 -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP tux 768M 498 99 381127 74 269712 48 2871 99 717109 50 +++++ +++ Latency 18368us 31063us 21281us 3017us 6875us 251ms Version 1.96 ------Sequential Create------ --------Random Create-------- tux -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ Latency 148us 588us 2792us 1547us 1543us 218us After: Version 1.96 ------Sequential Output------ --Sequential Input- --Random- Concurrency 2 -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP tux 768M 499 99 459779 73 350689 54 2997 99 860395 58 +++++ +++ Latency 17194us 14619us 26358us 4055us 7890us 44122us Version 1.96 ------Sequential Create------ --------Random Create-------- tux -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ Latency 135us 567us 2564us 134us 1500us 231us Signed-off-by: Sasha Levin --- tools/kvm/Makefile | 1 + tools/kvm/include/kvm/ioeventfd.h | 27 ++++++++ tools/kvm/ioeventfd.c | 128 +++++++++++++++++++++++++++++++++++++ tools/kvm/kvm-run.c | 4 + 4 files changed, 160 insertions(+), 0 deletions(-) create mode 100644 tools/kvm/include/kvm/ioeventfd.h create mode 100644 tools/kvm/ioeventfd.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index 2ebc86c..e7ceb5c 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -48,6 +48,7 @@ OBJS += irq.o OBJS += rbtree.o OBJS += util/rbtree-interval.o OBJS += virtio/9p.o +OBJS += ioeventfd.o FLAGS_BFD=$(CFLAGS) -lbfd diff --git a/tools/kvm/include/kvm/ioeventfd.h b/tools/kvm/include/kvm/ioeventfd.h new file mode 100644 index 0000000..df01750 --- /dev/null +++ b/tools/kvm/include/kvm/ioeventfd.h @@ -0,0 +1,27 @@ +#ifndef KVM__IOEVENTFD_H +#define KVM__IOEVENTFD_H + +#include +#include +#include + +struct kvm; + +struct ioevent { + u64 io_addr; + u8 io_len; + void (*fn)(struct kvm *kvm, void *ptr); + struct kvm *fn_kvm; + void *fn_ptr; + int fd; + u64 datamatch; + + struct list_head list; +}; + +void ioeventfd__init(void); +void ioeventfd__start(void); +void ioeventfd__add_event(struct ioevent *ioevent); +void ioeventfd__del_event(u64 addr, u64 datamatch); + +#endif diff --git a/tools/kvm/ioeventfd.c b/tools/kvm/ioeventfd.c new file mode 100644 index 0000000..3a240e4 --- /dev/null +++ b/tools/kvm/ioeventfd.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kvm/ioeventfd.h" +#include "kvm/kvm.h" +#include "kvm/util.h" + +#define IOEVENTFD_MAX_EVENTS 20 + +static struct epoll_event events[IOEVENTFD_MAX_EVENTS]; +static int epoll_fd; +static LIST_HEAD(used_ioevents); + +void ioeventfd__init(void) +{ + epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS); + if (epoll_fd < 0) + die("Failed creating epoll fd"); +} + +void ioeventfd__add_event(struct ioevent *ioevent) +{ + struct kvm_ioeventfd kvm_ioevent; + struct epoll_event epoll_event; + struct ioevent *new_ioevent; + int event; + + new_ioevent = malloc(sizeof(*new_ioevent)); + if (new_ioevent == NULL) + die("Failed allocating memory for new ioevent"); + + *new_ioevent = *ioevent; + event = new_ioevent->fd; + + kvm_ioevent = (struct kvm_ioeventfd) { + .addr = ioevent->io_addr, + .len = ioevent->io_len, + .datamatch = ioevent->datamatch, + .fd = event, + .flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH, + }; + + if (ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent) != 0) + die("Failed creating new ioeventfd"); + + epoll_event = (struct epoll_event) { + .events = EPOLLIN, + .data.ptr = new_ioevent, + }; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event) != 0) + die("Failed assigning new event to the epoll fd"); + + list_add_tail(&new_ioevent->list, &used_ioevents); +} + +void ioeventfd__del_event(u64 addr, u64 datamatch) +{ + struct kvm_ioeventfd kvm_ioevent; + struct ioevent *ioevent; + u8 found = 0; + + list_for_each_entry(ioevent, &used_ioevents, list) { + if (ioevent->io_addr == addr) { + found = 1; + break; + } + } + + if (found == 0 || ioevent == NULL) + return; + + kvm_ioevent = (struct kvm_ioeventfd) { + .addr = ioevent->io_addr, + .len = ioevent->io_len, + .datamatch = ioevent->datamatch, + .flags = KVM_IOEVENTFD_FLAG_PIO + | KVM_IOEVENTFD_FLAG_DEASSIGN + | KVM_IOEVENTFD_FLAG_DATAMATCH, + }; + + ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); + + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL); + + list_del(&ioevent->list); + + close(ioevent->fd); + free(ioevent); +} + +static void *ioeventfd__thread(void *param) +{ + for (;;) { + int nfds, i; + + nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); + for (i = 0; i < nfds; i++) { + u64 tmp; + struct ioevent *ioevent; + + ioevent = events[i].data.ptr; + + if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) + die("Failed reading event"); + + ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); + } + } + + return NULL; +} + +void ioeventfd__start(void) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, ioeventfd__thread, NULL) != 0) + die("Failed starting ioeventfd thread"); +} diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index f384ddd..48b8e70 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -29,6 +29,7 @@ #include #include #include +#include /* header files for gitish interface */ #include @@ -505,6 +506,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) kvm = kvm__init(kvm_dev, ram_size); + ioeventfd__init(); + max_cpus = kvm__max_cpus(kvm); if (nrcpus > max_cpus) { @@ -612,6 +615,7 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) vesa__init(kvm); thread_pool__init(nr_online_cpus); + ioeventfd__start(); for (i = 0; i < nrcpus; i++) { if (pthread_create(&kvm_cpus[i]->thread, NULL, kvm_cpu_thread, kvm_cpus[i]) != 0)