summaryrefslogtreecommitdiffstats
path: root/drivers/vhost
diff options
context:
space:
mode:
authorIgor Mammedov <imammedo@redhat.com>2015-06-16 12:33:35 -0400
committerMichael S. Tsirkin <mst@redhat.com>2015-07-01 04:12:12 -0400
commitbcfeacab45e6d419c6bafc0e57ea4b1125e23231 (patch)
treec994f9533d20d043525fd5730629ed3a97bd60b0 /drivers/vhost
parent8b0a9d42301e45d501d751074a6f767fded680b1 (diff)
vhost: use binary search instead of linear in find_region()
For default region layouts performance stays the same as linear search i.e. it takes around 210ns average for translate_desc() that inlines find_region(). But it scales better with larger amount of regions, 235ns BS vs 300ns LS with 55 memory regions and it will be about the same values when allowed number of slots is increased to 509 like it has been done in kvm. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'drivers/vhost')
-rw-r--r--drivers/vhost/vhost.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 9e8e004bb1c3..71bb46813031 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -25,6 +25,7 @@
25#include <linux/kthread.h> 25#include <linux/kthread.h>
26#include <linux/cgroup.h> 26#include <linux/cgroup.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/sort.h>
28 29
29#include "vhost.h" 30#include "vhost.h"
30 31
@@ -663,6 +664,16 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq)
663} 664}
664EXPORT_SYMBOL_GPL(vhost_vq_access_ok); 665EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
665 666
667static int vhost_memory_reg_sort_cmp(const void *p1, const void *p2)
668{
669 const struct vhost_memory_region *r1 = p1, *r2 = p2;
670 if (r1->guest_phys_addr < r2->guest_phys_addr)
671 return 1;
672 if (r1->guest_phys_addr > r2->guest_phys_addr)
673 return -1;
674 return 0;
675}
676
666static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) 677static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
667{ 678{
668 struct vhost_memory mem, *newmem, *oldmem; 679 struct vhost_memory mem, *newmem, *oldmem;
@@ -682,9 +693,11 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
682 memcpy(newmem, &mem, size); 693 memcpy(newmem, &mem, size);
683 if (copy_from_user(newmem->regions, m->regions, 694 if (copy_from_user(newmem->regions, m->regions,
684 mem.nregions * sizeof *m->regions)) { 695 mem.nregions * sizeof *m->regions)) {
685 kfree(newmem); 696 kvfree(newmem);
686 return -EFAULT; 697 return -EFAULT;
687 } 698 }
699 sort(newmem->regions, newmem->nregions, sizeof(*newmem->regions),
700 vhost_memory_reg_sort_cmp, NULL);
688 701
689 if (!memory_access_ok(d, newmem, 0)) { 702 if (!memory_access_ok(d, newmem, 0)) {
690 kfree(newmem); 703 kfree(newmem);
@@ -992,17 +1005,22 @@ EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
992static const struct vhost_memory_region *find_region(struct vhost_memory *mem, 1005static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
993 __u64 addr, __u32 len) 1006 __u64 addr, __u32 len)
994{ 1007{
995 struct vhost_memory_region *reg; 1008 const struct vhost_memory_region *reg;
996 int i; 1009 int start = 0, end = mem->nregions;
997 1010
998 /* linear search is not brilliant, but we really have on the order of 6 1011 while (start < end) {
999 * regions in practice */ 1012 int slot = start + (end - start) / 2;
1000 for (i = 0; i < mem->nregions; ++i) { 1013 reg = mem->regions + slot;
1001 reg = mem->regions + i; 1014 if (addr >= reg->guest_phys_addr)
1002 if (reg->guest_phys_addr <= addr && 1015 end = slot;
1003 reg->guest_phys_addr + reg->memory_size - 1 >= addr) 1016 else
1004 return reg; 1017 start = slot + 1;
1005 } 1018 }
1019
1020 reg = mem->regions + start;
1021 if (addr >= reg->guest_phys_addr &&
1022 reg->guest_phys_addr + reg->memory_size > addr)
1023 return reg;
1006 return NULL; 1024 return NULL;
1007} 1025}
1008 1026