Stefano Stabellini
2011-May-18 17:51 UTC
[Xen-devel] [PATCH 0 of 5] xen mapcache fixes and improvements
Hi all, this patch series introduces a series of fixes and improvements to the xen mapcache in qemu. The list of patches with a diffstat follows: Stefano Stabellini (5): xen: fix qemu_map_cache with size != MCACHE_BUCKET_SIZE xen: remove qemu_map_cache_unlock xen: remove xen_map_block and xen_unmap_block exec.c: refactor cpu_physical_memory_map xen: mapcache performance improvements cpu-common.h | 1 + exec.c | 87 +++++++++++++++---------------- xen-mapcache-stub.c | 8 --- xen-mapcache.c | 141 +++++++++++++++++++++++--------------------------- xen-mapcache.h | 13 ----- 5 files changed, 108 insertions(+), 142 deletions(-) Most of them are just straightforward cleanups and only touch Xen code. The first patch fixes the current mapcache implementation that even though provides a size parameter isn''t actually able to cope with sizes other than 0 or the bucket size. The second and the third patch remove some not very useful mapcache related functions and replace them with proper calls to qemu_map_cache and qemu_invalidate_entry. In particular in the case of xen_map_block and xen_unmap_block it wasn''t possible before because of the size problem describe above. The fourth patch refactors cpu_physical_memory_map to simplify the implementation and replace multiple calls to qemu_get_ram_ptr with a single call to a new function that takes an address and a size a parameters. Hopefully the changes make the function easier to understand and more efficient. Comments and reviews on this patch are very very welcome. The last patch introduces few interesting performance improvements: assuming that qemu_get_ram_ptr is only called to perform one of the following two actions: 1) map an entire block other than the main ram block (offset == 0); 2) map a single page in the main ram block to issue a read or a write straight after the call; we can make the conscious decision of avoid locking the mapcache entries for case 2). Then considering that qemu_put_ram_ptr is called to unmap pages in the same two cases as before, and considering that we don''t need to unmap unlocked mapcache entries, we can avoid calling qemu_invalidate_entry completely. A git tree with the patch series applied to the latest qemu is available here: git://xenbits.xen.org/people/sstabellini/qemu-dm.git mapcache_fixes - Stefano _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-May-18 17:52 UTC
[Xen-devel] [PATCH 1/5] xen: fix qemu_map_cache with size != MCACHE_BUCKET_SIZE
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Fix the implementation of qemu_map_cache: correctly support size arguments different from 0 or MCACHE_BUCKET_SIZE. The new implementation supports locked mapcache entries with size multiple of MCACHE_BUCKET_SIZE. qemu_invalidate_entry can correctly find and unmap these "large" mapcache entries given that the virtual address passed to qemu_invalidate_entry is the same returned by qemu_map_cache when the locked mapcache entry was created. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- xen-mapcache.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 65 insertions(+), 12 deletions(-) diff --git a/xen-mapcache.c b/xen-mapcache.c index 349cc62..90fbd49 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -43,14 +43,16 @@ typedef struct MapCacheEntry { target_phys_addr_t paddr_index; uint8_t *vaddr_base; - DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT); + unsigned long *valid_mapping; uint8_t lock; + target_phys_addr_t size; struct MapCacheEntry *next; } MapCacheEntry; typedef struct MapCacheRev { uint8_t *vaddr_req; target_phys_addr_t paddr_index; + target_phys_addr_t size; QTAILQ_ENTRY(MapCacheRev) next; } MapCacheRev; @@ -68,6 +70,15 @@ typedef struct MapCache { static MapCache *mapcache; +static inline int test_bits(int nr, int size, const unsigned long *addr) +{ + unsigned long res = find_next_zero_bit(addr, size + nr, nr); + if (res >= nr + size) + return 1; + else + return 0; +} + void qemu_map_cache_init(void) { unsigned long size; @@ -115,11 +126,15 @@ static void qemu_remap_bucket(MapCacheEntry *entry, err = qemu_mallocz(nb_pfn * sizeof (int)); if (entry->vaddr_base != NULL) { - if (munmap(entry->vaddr_base, size) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } } + if (entry->valid_mapping != NULL) { + qemu_free(entry->valid_mapping); + entry->valid_mapping = NULL; + } for (i = 0; i < nb_pfn; i++) { pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i; @@ -134,6 +149,9 @@ static void qemu_remap_bucket(MapCacheEntry *entry, entry->vaddr_base = vaddr_base; entry->paddr_index = address_index; + entry->size = size; + entry->valid_mapping = (unsigned long *) qemu_mallocz(sizeof(unsigned long) * + BITS_TO_LONGS(size >> XC_PAGE_SHIFT)); bitmap_zero(entry->valid_mapping, nb_pfn); for (i = 0; i < nb_pfn; i++) { @@ -151,32 +169,47 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u MapCacheEntry *entry, *pentry = NULL; target_phys_addr_t address_index = phys_addr >> MCACHE_BUCKET_SHIFT; target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1); + target_phys_addr_t __size = size; trace_qemu_map_cache(phys_addr); - if (address_index == mapcache->last_address_index && !lock) { + if (address_index == mapcache->last_address_index && !lock && !__size) { trace_qemu_map_cache_return(mapcache->last_address_vaddr + address_offset); return mapcache->last_address_vaddr + address_offset; } + /* size is always a multiple of MCACHE_BUCKET_SIZE */ + if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE) + __size += MCACHE_BUCKET_SIZE; + if (__size % MCACHE_BUCKET_SIZE) + __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE); + if (!__size) + __size = MCACHE_BUCKET_SIZE; + entry = &mapcache->entry[address_index % mapcache->nr_buckets]; - while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) { + while (entry && entry->lock && entry->vaddr_base && + (entry->paddr_index != address_index || entry->size != __size || + !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping))) { pentry = entry; entry = entry->next; } if (!entry) { entry = qemu_mallocz(sizeof (MapCacheEntry)); pentry->next = entry; - qemu_remap_bucket(entry, size ? : MCACHE_BUCKET_SIZE, address_index); + qemu_remap_bucket(entry, __size, address_index); } else if (!entry->lock) { if (!entry->vaddr_base || entry->paddr_index != address_index || - !test_bit(address_offset >> XC_PAGE_SHIFT, entry->valid_mapping)) { - qemu_remap_bucket(entry, size ? : MCACHE_BUCKET_SIZE, address_index); + entry->size != __size || + !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping)) { + qemu_remap_bucket(entry, __size, address_index); } } - if (!test_bit(address_offset >> XC_PAGE_SHIFT, entry->valid_mapping)) { + if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping)) { mapcache->last_address_index = -1; trace_qemu_map_cache_return(NULL); return NULL; @@ -189,6 +222,7 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u entry->lock++; reventry->vaddr_req = mapcache->last_address_vaddr + address_offset; reventry->paddr_index = mapcache->last_address_index; + reventry->size = entry->size; QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next); } @@ -231,13 +265,16 @@ void qemu_map_cache_unlock(void *buffer) ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { + MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; target_phys_addr_t paddr_index; + target_phys_addr_t size; int found = 0; QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { if (reventry->vaddr_req == ptr) { paddr_index = reventry->paddr_index; + size = reventry->size; found = 1; break; } @@ -252,7 +289,17 @@ ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) return 0; } - return paddr_index << MCACHE_BUCKET_SHIFT; + entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; + while (entry && (entry->paddr_index != paddr_index || entry->size != size)) { + pentry = entry; + entry = entry->next; + } + if (!entry) { + DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr); + return 0; + } + return (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + + ((unsigned long) ptr - (unsigned long) entry->vaddr_base); } void qemu_invalidate_entry(uint8_t *buffer) @@ -260,6 +307,7 @@ void qemu_invalidate_entry(uint8_t *buffer) MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; target_phys_addr_t paddr_index; + target_phys_addr_t size; int found = 0; if (mapcache->last_address_vaddr == buffer) { @@ -269,6 +317,7 @@ void qemu_invalidate_entry(uint8_t *buffer) QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { if (reventry->vaddr_req == buffer) { paddr_index = reventry->paddr_index; + size = reventry->size; found = 1; break; } @@ -284,7 +333,7 @@ void qemu_invalidate_entry(uint8_t *buffer) qemu_free(reventry); entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; - while (entry && entry->paddr_index != paddr_index) { + while (entry && (entry->paddr_index != paddr_index || entry->size != size)) { pentry = entry; entry = entry->next; } @@ -298,10 +347,11 @@ void qemu_invalidate_entry(uint8_t *buffer) } pentry->next = entry->next; - if (munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } + qemu_free(entry->valid_mapping); qemu_free(entry); } @@ -328,13 +378,16 @@ void qemu_invalidate_map_cache(void) continue; } - if (munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } entry->paddr_index = 0; entry->vaddr_base = NULL; + entry->size = 0; + qemu_free(entry->valid_mapping); + entry->valid_mapping = NULL; } mapcache->last_address_index = -1; -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-May-18 17:52 UTC
[Xen-devel] [PATCH 2/5] xen: remove qemu_map_cache_unlock
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> There is no need for qemu_map_cache_unlock, just use qemu_invalidate_entry instead. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- exec.c | 2 +- xen-mapcache-stub.c | 4 ---- xen-mapcache.c | 33 --------------------------------- xen-mapcache.h | 1 - 4 files changed, 1 insertions(+), 39 deletions(-) diff --git a/exec.c b/exec.c index a6df2d6..01498d2 100644 --- a/exec.c +++ b/exec.c @@ -3126,7 +3126,7 @@ void qemu_put_ram_ptr(void *addr) xen_unmap_block(block->host, block->length); block->host = NULL; } else { - qemu_map_cache_unlock(addr); + qemu_invalidate_entry(addr); } } } diff --git a/xen-mapcache-stub.c b/xen-mapcache-stub.c index 7c14b3d..60f712b 100644 --- a/xen-mapcache-stub.c +++ b/xen-mapcache-stub.c @@ -22,10 +22,6 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u return qemu_get_ram_ptr(phys_addr); } -void qemu_map_cache_unlock(void *buffer) -{ -} - ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { return -1; diff --git a/xen-mapcache.c b/xen-mapcache.c index 90fbd49..57fe24d 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -230,39 +230,6 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u return mapcache->last_address_vaddr + address_offset; } -void qemu_map_cache_unlock(void *buffer) -{ - MapCacheEntry *entry = NULL, *pentry = NULL; - MapCacheRev *reventry; - target_phys_addr_t paddr_index; - int found = 0; - - QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - if (reventry->vaddr_req == buffer) { - paddr_index = reventry->paddr_index; - found = 1; - break; - } - } - if (!found) { - return; - } - QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next); - qemu_free(reventry); - - entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; - while (entry && entry->paddr_index != paddr_index) { - pentry = entry; - entry = entry->next; - } - if (!entry) { - return; - } - if (entry->lock > 0) { - entry->lock--; - } -} - ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { MapCacheEntry *entry = NULL, *pentry = NULL; diff --git a/xen-mapcache.h b/xen-mapcache.h index 339444c..b89b8f9 100644 --- a/xen-mapcache.h +++ b/xen-mapcache.h @@ -14,7 +14,6 @@ void qemu_map_cache_init(void); uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock); -void qemu_map_cache_unlock(void *phys_addr); ram_addr_t qemu_ram_addr_from_mapcache(void *ptr); void qemu_invalidate_entry(uint8_t *buffer); void qemu_invalidate_map_cache(void); -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-May-18 17:52 UTC
[Xen-devel] [PATCH 3/5] xen: remove xen_map_block and xen_unmap_block
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Replace xen_map_block with qemu_map_cache with the appropriate locking and size parameters. Replace xen_unmap_block with qemu_invalidate_entry. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- exec.c | 18 +++--------------- xen-mapcache-stub.c | 4 ---- xen-mapcache.c | 31 ------------------------------- xen-mapcache.h | 12 ------------ 4 files changed, 3 insertions(+), 62 deletions(-) diff --git a/exec.c b/exec.c index 01498d2..56bc636 100644 --- a/exec.c +++ b/exec.c @@ -3068,7 +3068,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr) if (block->offset == 0) { return qemu_map_cache(addr, 0, 1); } else if (block->host == NULL) { - block->host = xen_map_block(block->offset, block->length); + block->host = qemu_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3097,7 +3097,7 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) if (block->offset == 0) { return qemu_map_cache(addr, 0, 1); } else if (block->host == NULL) { - block->host = xen_map_block(block->offset, block->length); + block->host = qemu_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3115,19 +3115,7 @@ void qemu_put_ram_ptr(void *addr) trace_qemu_put_ram_ptr(addr); if (xen_mapcache_enabled()) { - RAMBlock *block; - - QLIST_FOREACH(block, &ram_list.blocks, next) { - if (addr == block->host) { - break; - } - } - if (block && block->host) { - xen_unmap_block(block->host, block->length); - block->host = NULL; - } else { - qemu_invalidate_entry(addr); - } + qemu_invalidate_entry(block->host); } } diff --git a/xen-mapcache-stub.c b/xen-mapcache-stub.c index 60f712b..8a2380a 100644 --- a/xen-mapcache-stub.c +++ b/xen-mapcache-stub.c @@ -34,7 +34,3 @@ void qemu_invalidate_map_cache(void) void qemu_invalidate_entry(uint8_t *buffer) { } -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size) -{ - return NULL; -} diff --git a/xen-mapcache.c b/xen-mapcache.c index 57fe24d..fac47cd 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -362,34 +362,3 @@ void qemu_invalidate_map_cache(void) mapcache_unlock(); } - -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size) -{ - uint8_t *vaddr_base; - xen_pfn_t *pfns; - int *err; - unsigned int i; - target_phys_addr_t nb_pfn = size >> XC_PAGE_SHIFT; - - trace_xen_map_block(phys_addr, size); - phys_addr >>= XC_PAGE_SHIFT; - - pfns = qemu_mallocz(nb_pfn * sizeof (xen_pfn_t)); - err = qemu_mallocz(nb_pfn * sizeof (int)); - - for (i = 0; i < nb_pfn; i++) { - pfns[i] = phys_addr + i; - } - - vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE, - pfns, err, nb_pfn); - if (vaddr_base == NULL) { - perror("xc_map_foreign_bulk"); - exit(-1); - } - - qemu_free(pfns); - qemu_free(err); - - return vaddr_base; -} diff --git a/xen-mapcache.h b/xen-mapcache.h index b89b8f9..5fc9eb5 100644 --- a/xen-mapcache.h +++ b/xen-mapcache.h @@ -18,18 +18,6 @@ ram_addr_t qemu_ram_addr_from_mapcache(void *ptr); void qemu_invalidate_entry(uint8_t *buffer); void qemu_invalidate_map_cache(void); -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size); - -static inline void xen_unmap_block(void *addr, ram_addr_t size) -{ - trace_xen_unmap_block(addr, size); - - if (munmap(addr, size) != 0) { - hw_error("xen_unmap_block: %s", strerror(errno)); - } -} - - #define mapcache_lock() ((void)0) #define mapcache_unlock() ((void)0) -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-May-18 17:52 UTC
[Xen-devel] [PATCH 4/5] exec.c: refactor cpu_physical_memory_map
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Introduce qemu_ram_ptr_length that takes an address and a size as parameters rather than just an address. Refactor cpu_physical_memory_map so that we call qemu_ram_ptr_length only once rather than calling qemu_get_ram_ptr one time per page. This is not only more efficient but also tries to simplify the logic of the function. Currently we are relying on the fact that all the pages are mapped contiguously in qemu''s address space: we have a check to make sure that the virtual address returned by qemu_get_ram_ptr from the second call on is consecutive. Now we are making this more explicit replacing all the calls to qemu_get_ram_ptr with a single call to qemu_ram_ptr_length passing a size argument. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> CC: agraf@suse.de CC: anthony@codemonkey.ws --- cpu-common.h | 1 + exec.c | 51 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index 151c32c..085aacb 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -64,6 +64,7 @@ void qemu_ram_free(ram_addr_t addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr(ram_addr_t addr); +void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size); /* Same but slower, to use for migration, where the order of * RAMBlocks must not change. */ void *qemu_safe_ram_ptr(ram_addr_t addr); diff --git a/exec.c b/exec.c index 56bc636..ee9316e 100644 --- a/exec.c +++ b/exec.c @@ -3110,6 +3110,31 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) return NULL; } +/* Return a host pointer to guest''s ram. Similar to qemu_get_ram_ptr + * but takes a size argument */ +void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size) +{ + if (xen_mapcache_enabled()) + return qemu_map_cache(addr, *size, 1); + else { + RAMBlock *block; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (addr - block->offset < block->length) { + if (addr - block->offset + *size > block->length) + *size = block->length - addr + block->offset; + return block->host + (addr - block->offset); + } + } + + fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); + abort(); + + *size = 0; + return NULL; + } +} + void qemu_put_ram_ptr(void *addr) { trace_qemu_put_ram_ptr(addr); @@ -3971,14 +3996,12 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, int is_write) { target_phys_addr_t len = *plen; - target_phys_addr_t done = 0; + target_phys_addr_t todo = 0; int l; - uint8_t *ret = NULL; - uint8_t *ptr; target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - unsigned long addr1; + target_phys_addr_t addr1 = addr; while (len > 0) { page = addr & TARGET_PAGE_MASK; @@ -3993,7 +4016,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, } if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { - if (done || bounce.buffer) { + if (todo || bounce.buffer) { break; } bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); @@ -4002,23 +4025,17 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, if (!is_write) { cpu_physical_memory_read(addr, bounce.buffer, l); } - ptr = bounce.buffer; - } else { - addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); - ptr = qemu_get_ram_ptr(addr1); - } - if (!done) { - ret = ptr; - } else if (ret + done != ptr) { - break; + + *plen = l; + return bounce.buffer; } len -= l; addr += l; - done += l; + todo += l; } - *plen = done; - return ret; + *plen = todo; + return qemu_ram_ptr_length(addr1, plen); } /* Unmaps a memory region previously mapped by cpu_physical_memory_map(). -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
<stefano.stabellini@eu.citrix.com>
2011-May-18 17:52 UTC
[Xen-devel] [PATCH 5/5] xen: mapcache performance improvements
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Use qemu_invalidate_entry in cpu_physical_memory_unmap. Do not lock mapcache entries in qemu_get_ram_ptr if the address falls in the ramblock with offset == 0. We don''t need to do that because the callers of qemu_get_ram_ptr either try to map an entire block, other from the main ramblock, or until the end of a page to implement a single read or write in the main ramblock. If we don''t lock mapcache entries in qemu_get_ram_ptr we don''t need to call qemu_invalidate_entry in qemu_put_ram_ptr anymore because we can leave with few long lived block mappings requested by devices. Also move the call to qemu_ram_addr_from_mapcache at the beginning of qemu_ram_addr_from_host. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- exec.c | 28 ++++++++++------------------ 1 files changed, 10 insertions(+), 18 deletions(-) diff --git a/exec.c b/exec.c index ee9316e..76ed071 100644 --- a/exec.c +++ b/exec.c @@ -3064,9 +3064,10 @@ void *qemu_get_ram_ptr(ram_addr_t addr) if (xen_mapcache_enabled()) { /* We need to check if the requested address is in the RAM * because we don''t want to map the entire memory in QEMU. + * In that case just map until the end of the page. */ if (block->offset == 0) { - return qemu_map_cache(addr, 0, 1); + return qemu_map_cache(addr, 0, 0); } else if (block->host == NULL) { block->host = qemu_map_cache(block->offset, block->length, 1); } @@ -3093,9 +3094,10 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) if (xen_mapcache_enabled()) { /* We need to check if the requested address is in the RAM * because we don''t want to map the entire memory in QEMU. + * In that case just map until the end of the page. */ if (block->offset == 0) { - return qemu_map_cache(addr, 0, 1); + return qemu_map_cache(addr, 0, 0); } else if (block->host == NULL) { block->host = qemu_map_cache(block->offset, block->length, 1); } @@ -3138,10 +3140,6 @@ void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size) void qemu_put_ram_ptr(void *addr) { trace_qemu_put_ram_ptr(addr); - - if (xen_mapcache_enabled()) { - qemu_invalidate_entry(block->host); - } } int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) @@ -3149,6 +3147,11 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) RAMBlock *block; uint8_t *host = ptr; + if (xen_mapcache_enabled()) { + *ram_addr = qemu_ram_addr_from_mapcache(ptr); + return 0; + } + QLIST_FOREACH(block, &ram_list.blocks, next) { /* This case append when the block is not mapped. */ if (block->host == NULL) { @@ -3160,11 +3163,6 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) } } - if (xen_mapcache_enabled()) { - *ram_addr = qemu_ram_addr_from_mapcache(ptr); - return 0; - } - return -1; } @@ -4065,13 +4063,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, } } if (xen_mapcache_enabled()) { - uint8_t *buffer1 = buffer; - uint8_t *end_buffer = buffer + len; - - while (buffer1 < end_buffer) { - qemu_put_ram_ptr(buffer1); - buffer1 += TARGET_PAGE_SIZE; - } + qemu_invalidate_entry(buffer); } return; } -- 1.7.2.3 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Paolo Bonzini
2011-May-18 21:56 UTC
[Xen-devel] Re: [PATCH 4/5] exec.c: refactor cpu_physical_memory_map
On 05/18/2011 07:52 PM, stefano.stabellini@eu.citrix.com wrote:> From: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > > Introduce qemu_ram_ptr_length that takes an address and a size as > parameters rather than just an address. > > Refactor cpu_physical_memory_map so that we call qemu_ram_ptr_length only > once rather than calling qemu_get_ram_ptr one time per page. > This is not only more efficient but also tries to simplify the logic of > the function. > Currently we are relying on the fact that all the pages are mapped > contiguously in qemu''s address space: we have a check to make sure that > the virtual address returned by qemu_get_ram_ptr from the second call on > is consecutive. Now we are making this more explicit replacing all the > calls to qemu_get_ram_ptr with a single call to qemu_ram_ptr_length > passing a size argument.Would the interface at http://permalink.gmane.org/gmane.comp.emulators.qemu/101475 work for you alternatively? Paolo _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2011-May-19 17:21 UTC
[Xen-devel] Re: [PATCH 4/5] exec.c: refactor cpu_physical_memory_map
On Wed, 18 May 2011, Paolo Bonzini wrote:> On 05/18/2011 07:52 PM, stefano.stabellini@eu.citrix.com wrote: > > From: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > > > > Introduce qemu_ram_ptr_length that takes an address and a size as > > parameters rather than just an address. > > > > Refactor cpu_physical_memory_map so that we call qemu_ram_ptr_length only > > once rather than calling qemu_get_ram_ptr one time per page. > > This is not only more efficient but also tries to simplify the logic of > > the function. > > Currently we are relying on the fact that all the pages are mapped > > contiguously in qemu''s address space: we have a check to make sure that > > the virtual address returned by qemu_get_ram_ptr from the second call on > > is consecutive. Now we are making this more explicit replacing all the > > calls to qemu_get_ram_ptr with a single call to qemu_ram_ptr_length > > passing a size argument. > > Would the interface at > http://permalink.gmane.org/gmane.comp.emulators.qemu/101475 work for you > alternatively?Unfortunately that interface doesn''t solve the problem I am trying to address: cpu_physical_memory_map_fast calls cpu_physical_memory_map_internal that still calls qemu_get_ram_ptr in a loop. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel