tools/libs/guest: Use superpages where possible on migrate/resume

Right now on migrate/resume, all guest memory is allocated with 4k
small pages.  This was an intended oversight in the original Migration
v2 implementation.

With some test memory program stressing TLB (many small random memory
accesses) superpages can show a 15% performance improvement.

On the first memory iteration the sender is currently sending memory
in 4MB aligned chunks of GFN space which allows the receiver to
allocate most pages as 2MB superpages instead of single 4KB pages.

This change does not handle 1GB superpages as this will require
changes to the migration protocol.

Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
This commit is contained in:
Frediano Ziglio authored and Andrew Cooper committed 2025-09-29 21:32:37 +02:00
1 parent 45c6090783
commit 50baf2d9f7
1 file changed
+54 -3
+54 -3
View File
@@ -129,6 +129,35 @@ static int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn)
return 0;
}
#if defined(__i386__) || defined(__x86_64__)
/* Order of the smallest superpage */
#define SMALL_SUPERPAGE_ORDER 9
#else
#error Define SMALL_SUPERPAGE_ORDER for this platform
#endif
static bool populate_small_superpage(struct xc_sr_context *ctx, xen_pfn_t gfn)
{
xen_pfn_t mfn = gfn;
if ( xc_domain_populate_physmap_exact(
ctx->xch, ctx->domid, 1, SMALL_SUPERPAGE_ORDER, 0, &mfn) )
return false;
/*
* XENMEM_populate_physmap has no coherent error semantics.
* Assume a failure here is ENOMEM, and fall back to allocating
* small pages.
*/
if ( mfn == INVALID_MFN )
return false;
for ( size_t i = 0; i < (1UL << SMALL_SUPERPAGE_ORDER); ++i )
ctx->restore.ops.set_gfn(ctx, gfn + i, mfn + i);
return true;
}
/*
* Given a set of pfns, obtain memory from Xen to fill the physmap for the
* unpopulated subset. If types is NULL, no page type checking is performed
@@ -142,6 +171,9 @@ int populate_pfns(struct xc_sr_context *ctx, unsigned int count,
*pfns = malloc(count * sizeof(*pfns));
unsigned int i, nr_pfns = 0;
int rc = -1;
xen_pfn_t prev = 0;
unsigned int num_contiguous = 0;
xen_pfn_t mask = (1ULL << SMALL_SUPERPAGE_ORDER) - 1;
if ( !mfns || !pfns )
{
@@ -152,14 +184,33 @@ int populate_pfns(struct xc_sr_context *ctx, unsigned int count,
for ( i = 0; i < count; ++i )
{
xen_pfn_t pfn = original_pfns[i];
if ( (!types || page_type_to_populate(types[i])) &&
!pfn_is_populated(ctx, original_pfns[i]) )
!pfn_is_populated(ctx, pfn) )
{
rc = pfn_set_populated(ctx, original_pfns[i]);
rc = pfn_set_populated(ctx, pfn);
if ( rc )
goto err;
pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i];
pfns[nr_pfns] = mfns[nr_pfns] = pfn;
++nr_pfns;
/*
* During the first pass for x86 HVM guests, PAGE_DATA
* records contain metadata about 4M aligned chunks of GFN
* space. Reconstruct 2M superpages where possible.
*/
if ( pfn != prev + 1 )
num_contiguous = 0;
num_contiguous++;
prev = pfn;
if ( num_contiguous > mask && (pfn & mask) == mask &&
populate_small_superpage(ctx, pfn - mask) )
{
nr_pfns -= mask + 1;
num_contiguous = 0;
}
}
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.