From 27af7d6ea5015e5ef1f7985eab94a8a218267a2b Mon Sep 17 00:00:00 2001 From: ChenLiang Date: Mon, 24 Nov 2014 19:55:47 +0800 Subject: xbzrle: optimize XBZRLE to decrease the cache misses Avoid hot pages being replaced by others to remarkably decrease cache misses Sample results with the test program which quote from xbzrle.txt ran in vm:(migrate bandwidth:1GE and xbzrle cache size 8MB) the test program: include include int main() { char *buf = (char *) calloc(4096, 4096); while (1) { int i; for (i = 0; i < 4096 * 4; i++) { buf[i * 4096 / 4]++; } printf("."); } } before this patch: virsh qemu-monitor-command test_vm '{"execute": "query-migrate"}' {"return":{"expected-downtime":1020,"xbzrle-cache":{"bytes":1108284, "cache-size":8388608,"cache-miss-rate":0.987013,"pages":18297,"overflow":8, "cache-miss":1228737},"status":"active","setup-time":10,"total-time":52398, "ram":{"total":12466991104,"remaining":1695744,"mbps":935.559472, "transferred":5780760580,"dirty-sync-counter":271,"duplicate":2878530, "dirty-pages-rate":29130,"skipped":0,"normal-bytes":5748592640, "normal":1403465}},"id":"libvirt-706"} 18k pages sent compressed in 52 seconds. cache-miss-rate is 98.7%, totally miss. after optimizing: virsh qemu-monitor-command test_vm '{"execute": "query-migrate"}' {"return":{"expected-downtime":2054,"xbzrle-cache":{"bytes":5066763, "cache-size":8388608,"cache-miss-rate":0.485924,"pages":194823,"overflow":0, "cache-miss":210653},"status":"active","setup-time":11,"total-time":18729, "ram":{"total":12466991104,"remaining":3895296,"mbps":937.663549, "transferred":1615042219,"dirty-sync-counter":98,"duplicate":2869840, "dirty-pages-rate":58781,"skipped":0,"normal-bytes":1588404224, "normal":387794}},"id":"libvirt-266"} 194k pages sent compressed in 18 seconds. The value of cache-miss-rate decrease to 48.59%. Signed-off-by: ChenLiang Signed-off-by: Gonglei Reviewed-by: Eric Blake Signed-off-by: Amit Shah --- page_cache.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'page_cache.c') diff --git a/page_cache.c b/page_cache.c index 89bb1ec3a0..aa681923c6 100644 --- a/page_cache.c +++ b/page_cache.c @@ -33,6 +33,9 @@ do { } while (0) #endif +/* the page in cache will not be replaced in two cycles */ +#define CACHED_PAGE_LIFETIME 2 + typedef struct CacheItem CacheItem; struct CacheItem { @@ -122,7 +125,8 @@ static size_t cache_get_cache_pos(const PageCache *cache, return pos; } -bool cache_is_cached(const PageCache *cache, uint64_t addr) +bool cache_is_cached(const PageCache *cache, uint64_t addr, + uint64_t current_age) { size_t pos; @@ -131,7 +135,12 @@ bool cache_is_cached(const PageCache *cache, uint64_t addr) pos = cache_get_cache_pos(cache, addr); - return (cache->page_cache[pos].it_addr == addr); + if (cache->page_cache[pos].it_addr == addr) { + /* update the it_age when the cache hit */ + cache->page_cache[pos].it_age = current_age; + return true; + } + return false; } static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) @@ -151,7 +160,8 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr) return cache_get_by_addr(cache, addr)->it_data; } -int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata) +int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, + uint64_t current_age) { CacheItem *it = NULL; @@ -162,6 +172,11 @@ int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata) /* actual update of entry */ it = cache_get_by_addr(cache, addr); + if (it->it_data && it->it_addr != addr && + it->it_age + CACHED_PAGE_LIFETIME > current_age) { + /* the cache page is fresh, don't replace it */ + return -1; + } /* allocate page */ if (!it->it_data) { it->it_data = g_try_malloc(cache->page_size); @@ -174,7 +189,7 @@ int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata) memcpy(it->it_data, pdata, cache->page_size); - it->it_age = ++cache->max_item_age; + it->it_age = current_age; it->it_addr = addr; return 0; -- cgit v1.2.3-55-g7522 From 1b826f277814dd9496fe3cc71cbe6ab7b203cadf Mon Sep 17 00:00:00 2001 From: ChenLiang Date: Mon, 24 Nov 2014 19:55:48 +0800 Subject: xbzrle: rebuild the cache_is_cached function Rebuild the cache_is_cached function by cache_get_by_addr. And drops the asserts because the caller is also asserting the same thing. Signed-off-by: ChenLiang Signed-off-by: Gonglei Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Amit Shah --- page_cache.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'page_cache.c') diff --git a/page_cache.c b/page_cache.c index aa681923c6..cf8878d1d7 100644 --- a/page_cache.c +++ b/page_cache.c @@ -125,24 +125,6 @@ static size_t cache_get_cache_pos(const PageCache *cache, return pos; } -bool cache_is_cached(const PageCache *cache, uint64_t addr, - uint64_t current_age) -{ - size_t pos; - - g_assert(cache); - g_assert(cache->page_cache); - - pos = cache_get_cache_pos(cache, addr); - - if (cache->page_cache[pos].it_addr == addr) { - /* update the it_age when the cache hit */ - cache->page_cache[pos].it_age = current_age; - return true; - } - return false; -} - static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr) { size_t pos; @@ -160,14 +142,26 @@ uint8_t *get_cached_data(const PageCache *cache, uint64_t addr) return cache_get_by_addr(cache, addr)->it_data; } +bool cache_is_cached(const PageCache *cache, uint64_t addr, + uint64_t current_age) +{ + CacheItem *it; + + it = cache_get_by_addr(cache, addr); + + if (it->it_addr == addr) { + /* update the it_age when the cache hit */ + it->it_age = current_age; + return true; + } + return false; +} + int cache_insert(PageCache *cache, uint64_t addr, const uint8_t *pdata, uint64_t current_age) { - CacheItem *it = NULL; - - g_assert(cache); - g_assert(cache->page_cache); + CacheItem *it; /* actual update of entry */ it = cache_get_by_addr(cache, addr); -- cgit v1.2.3-55-g7522