diff -u qemu-kvm-1.0+noroms/debian/changelog qemu-kvm-1.0+noroms/debian/changelog --- qemu-kvm-1.0+noroms/debian/changelog +++ qemu-kvm-1.0+noroms/debian/changelog @@ -1,3 +1,12 @@ +qemu-kvm (1.0+noroms-0ubuntu14.12) precise-proposed; urgency=low + + * migration-do-not-overwrite-zero-pages.patch, + call_madv_hugepage_for_guest_ram_allocations.patch: + Fix performance degradation after migrations, and savevm/loadvm. + (LP: #1100843) + + -- Chris J Arges Wed, 02 Oct 2013 16:26:27 -0500 + qemu-kvm (1.0+noroms-0ubuntu14.11) precise-proposed; urgency=low * debian/control and qemu-kvm.postinst: remove any g:--- acl on /dev/kvm diff -u qemu-kvm-1.0+noroms/debian/patches/series qemu-kvm-1.0+noroms/debian/patches/series --- qemu-kvm-1.0+noroms/debian/patches/series +++ qemu-kvm-1.0+noroms/debian/patches/series @@ -1,3 +1,5 @@ +call_madv_hugepage_for_guest_ram_allocations.patch +migration-do-not-overwrite-zero-pages.patch larger_default_ram_size.patch CVE-2011-2212-virtqueue-indirect-overflow.patch qemuifup-fix-paths.patch only in patch2: unchanged: --- qemu-kvm-1.0+noroms.orig/debian/patches/call_madv_hugepage_for_guest_ram_allocations.patch +++ qemu-kvm-1.0+noroms/debian/patches/call_madv_hugepage_for_guest_ram_allocations.patch @@ -0,0 +1,39 @@ +From ad0b5321f1f797274603ebbe20108b0750baee94 +From: Luiz Capitulino +Date: Fri Oct 5 16:47:57 2012 -0300 +Subject: [PATCH] Call MADV_HUGEPAGE for guest RAM allocations + +This makes it possible for QEMU to use transparent huge pages (THP) +when transparent_hugepage/enabled=madvise. Otherwise THP is only +used when it's enabled system wide. + +Signed-off-by: Luiz Capitulino +Signed-off-by: Anthony Liguori +(backported from commit ad0b5321f1f797274603ebbe20108b0750baee94) +Signed-off-by: Chris J Arges + +--- a/exec.c ++++ b/exec.c +@@ -2990,6 +2990,8 @@ ram_addr_t qemu_ram_alloc_from_ptr(Devic + memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS), + 0xff, size >> TARGET_PAGE_BITS); + ++ qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE); ++ + if (kvm_enabled()) + kvm_setup_guest_memory(new_block->host, size); + +--- a/osdep.h ++++ b/osdep.h +@@ -102,6 +102,11 @@ void qemu_vfree(void *ptr); + #else + #define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID + #endif ++#ifdef MADV_HUGEPAGE ++#define QEMU_MADV_HUGEPAGE MADV_HUGEPAGE ++#else ++#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID ++#endif + + #elif defined(CONFIG_POSIX_MADVISE) + only in patch2: unchanged: --- qemu-kvm-1.0+noroms.orig/debian/patches/migration-do-not-overwrite-zero-pages.patch +++ qemu-kvm-1.0+noroms/debian/patches/migration-do-not-overwrite-zero-pages.patch @@ -0,0 +1,152 @@ +From 211ea74022f51164a7729030b28eec90b6c99a08 Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Mon, 10 Jun 2013 12:14:20 +0200 +Subject: [PATCH] migration: do not overwrite zero pages + +on incoming migration do not memset pages to zero if they already read as zero. +this will allocate a new zero page and consume memory unnecessarily. even +if we madvise a MADV_DONTNEED later this will only deallocate the memory +asynchronously. + +Signed-off-by: Peter Lieven +Signed-off-by: Juan Quintela +(backported from commit 211ea74022f51164a7729030b28eec90b6c99a08) +Signed-off-by: Chris J Arges + +--- a/arch_init.c ++++ b/arch_init.c +@@ -109,6 +109,67 @@ static int is_dup_page(uint8_t *page, ui + return 1; + } + ++/* ++ * Searches for an area with non-zero content in a buffer ++ * ++ * Attention! The len must be a multiple of ++ * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR * sizeof(VECTYPE) ++ * and addr must be a multiple of sizeof(VECTYPE) due to ++ * restriction of optimizations in this function. ++ * ++ * can_use_buffer_find_nonzero_offset() can be used to check ++ * these requirements. ++ * ++ * The return value is the offset of the non-zero area rounded ++ * down to a multiple of sizeof(VECTYPE) for the first ++ * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR chunks and down to ++ * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR * sizeof(VECTYPE) ++ * afterwards. ++ * ++ * If the buffer is all zero the return value is equal to len. ++ */ ++ ++size_t buffer_find_nonzero_offset(const void *buf, size_t len) ++{ ++ const VECTYPE *p = buf; ++ const VECTYPE zero = (VECTYPE){0}; ++ size_t i; ++ ++ assert(can_use_buffer_find_nonzero_offset(buf, len)); ++ ++ if (!len) { ++ return 0; ++ } ++ ++ for (i = 0; i < BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR; i++) { ++ if (!ALL_EQ(p[i], zero)) { ++ return i * sizeof(VECTYPE); ++ } ++ } ++ ++ for (i = BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR; ++ i < len / sizeof(VECTYPE); ++ i += BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR) { ++ VECTYPE tmp0 = p[i + 0] | p[i + 1]; ++ VECTYPE tmp1 = p[i + 2] | p[i + 3]; ++ VECTYPE tmp2 = p[i + 4] | p[i + 5]; ++ VECTYPE tmp3 = p[i + 6] | p[i + 7]; ++ VECTYPE tmp01 = tmp0 | tmp1; ++ VECTYPE tmp23 = tmp2 | tmp3; ++ if (!ALL_EQ(tmp01 | tmp23, zero)) { ++ break; ++ } ++ } ++ ++ return i * sizeof(VECTYPE); ++} ++ ++static inline bool is_zero_page(uint8_t *p) ++{ ++ return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) == ++ TARGET_PAGE_SIZE; ++} ++ + static RAMBlock *last_block; + static ram_addr_t last_offset; + +@@ -440,13 +501,15 @@ int ram_load(QEMUFile *f, void *opaque, + } + + ch = qemu_get_byte(f); +- memset(host, ch, TARGET_PAGE_SIZE); ++ if (ch != 0 || !is_zero_page(host)) { ++ memset(host, ch, TARGET_PAGE_SIZE); + #ifndef _WIN32 +- if (ch == 0 && +- (!kvm_enabled() || kvm_has_sync_mmu())) { +- qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED); +- } ++ if (ch == 0 && ++ (!kvm_enabled() || kvm_has_sync_mmu())) { ++ qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED); ++ } + #endif ++ } + } else if (flags & RAM_SAVE_FLAG_PAGE) { + void *host; + +--- a/qemu-common.h ++++ b/qemu-common.h +@@ -341,6 +341,43 @@ static inline uint64_t muldiv64(uint64_t + return res.ll; + } + ++/* vector definitions */ ++#ifdef __ALTIVEC__ ++#include ++/* The altivec.h header says we're allowed to undef these for ++ * C++ compatibility. Here we don't care about C++, but we ++ * undef them anyway to avoid namespace pollution. ++ */ ++#undef vector ++#undef pixel ++#undef bool ++#define VECTYPE __vector unsigned char ++#define SPLAT(p) vec_splat(vec_ld(0, p), 0) ++#define ALL_EQ(v1, v2) vec_all_eq(v1, v2) ++/* altivec.h may redefine the bool macro as vector type. ++ * Reset it to POSIX semantics. */ ++#define bool _Bool ++#elif defined __SSE2__ ++#include ++#define VECTYPE __m128i ++#define SPLAT(p) _mm_set1_epi8(*(p)) ++#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF) ++#else ++#define VECTYPE unsigned long ++#define SPLAT(p) (*(p) * (~0UL / 255)) ++#define ALL_EQ(v1, v2) ((v1) == (v2)) ++#endif ++ ++#define BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR 8 ++static inline bool ++can_use_buffer_find_nonzero_offset(const void *buf, size_t len) ++{ ++ return (len % (BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR ++ * sizeof(VECTYPE)) == 0 ++ && ((uintptr_t) buf) % sizeof(VECTYPE) == 0); ++} ++size_t buffer_find_nonzero_offset(const void *buf, size_t len); ++ + #include "module.h" + + #endif