[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 39/51] migration: Teach PSS about host page
From: |
Juan Quintela |
Subject: |
[PATCH v2 39/51] migration: Teach PSS about host page |
Date: |
Mon, 5 Dec 2022 10:52:16 +0100 |
From: Peter Xu <peterx@redhat.com>
Migration code has a lot to do with host pages. Teaching PSS core about
the idea of host page helps a lot and makes the code clean. Meanwhile,
this prepares for the future changes that can leverage the new PSS helpers
that this patch introduces to send host page in another thread.
Three more fields are introduced for this:
(1) host_page_sending: this is set to true when QEMU is sending a host
page, false otherwise.
(2) host_page_{start|end}: these point to the start/end of host page
we're sending, and it's only valid when host_page_sending==true.
For example, when we look up the next dirty page on the ramblock, with
host_page_sending==true, we'll not try to look for anything beyond the
current host page boundary. This can be slightly efficient than current
code because currently we'll set pss->page to next dirty bit (which can be
over current host page boundary) and reset it to host page boundary if we
found it goes beyond that.
With above, we can easily make migration_bitmap_find_dirty() self contained
by updating pss->page properly. rs* parameter is removed because it's not
even used in old code.
When sending a host page, we should use the pss helpers like this:
- pss_host_page_prepare(pss): called before sending host page
- pss_within_range(pss): whether we're still working on the cur host page?
- pss_host_page_finish(pss): called after sending a host page
Then we can use ram_save_target_page() to save one small page.
Currently ram_save_host_page() is still the only user. If there'll be
another function to send host page (e.g. in return path thread) in the
future, it should follow the same style.
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
migration/ram.c | 95 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 76 insertions(+), 19 deletions(-)
diff --git a/migration/ram.c b/migration/ram.c
index f4cd9038f4..4d7b50ef79 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -481,6 +481,11 @@ struct PageSearchStatus {
* postcopy pages via postcopy preempt channel.
*/
bool postcopy_target_channel;
+ /* Whether we're sending a host page */
+ bool host_page_sending;
+ /* The start/end of current host page. Only valid if
host_page_sending==true */
+ unsigned long host_page_start;
+ unsigned long host_page_end;
};
typedef struct PageSearchStatus PageSearchStatus;
@@ -858,26 +863,38 @@ static int save_xbzrle_page(RAMState *rs, uint8_t
**current_data,
}
/**
- * migration_bitmap_find_dirty: find the next dirty page from start
+ * pss_find_next_dirty: find the next dirty page of current ramblock
*
- * Returns the page offset within memory region of the start of a dirty page
+ * This function updates pss->page to point to the next dirty page index
+ * within the ramblock to migrate, or the end of ramblock when nothing
+ * found. Note that when pss->host_page_sending==true it means we're
+ * during sending a host page, so we won't look for dirty page that is
+ * outside the host page boundary.
*
- * @rs: current RAM state
- * @rb: RAMBlock where to search for dirty pages
- * @start: page where we start the search
+ * @pss: the current page search status
*/
-static inline
-unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb,
- unsigned long start)
+static void pss_find_next_dirty(PageSearchStatus *pss)
{
+ RAMBlock *rb = pss->block;
unsigned long size = rb->used_length >> TARGET_PAGE_BITS;
unsigned long *bitmap = rb->bmap;
if (ramblock_is_ignored(rb)) {
- return size;
+ /* Points directly to the end, so we know no dirty page */
+ pss->page = size;
+ return;
}
- return find_next_bit(bitmap, size, start);
+ /*
+ * If during sending a host page, only look for dirty pages within the
+ * current host page being send.
+ */
+ if (pss->host_page_sending) {
+ assert(pss->host_page_end);
+ size = MIN(size, pss->host_page_end);
+ }
+
+ pss->page = find_next_bit(bitmap, size, pss->page);
}
static void migration_clear_memory_region_dirty_bitmap(RAMBlock *rb,
@@ -1563,7 +1580,9 @@ static bool find_dirty_block(RAMState *rs,
PageSearchStatus *pss, bool *again)
pss->postcopy_requested = false;
pss->postcopy_target_channel = RAM_CHANNEL_PRECOPY;
- pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page);
+ /* Update pss->page for the next dirty bit in ramblock */
+ pss_find_next_dirty(pss);
+
if (pss->complete_round && pss->block == rs->last_seen_block &&
pss->page >= rs->last_page) {
/*
@@ -2452,6 +2471,44 @@ static void postcopy_preempt_reset_channel(RAMState *rs)
}
}
+/* Should be called before sending a host page */
+static void pss_host_page_prepare(PageSearchStatus *pss)
+{
+ /* How many guest pages are there in one host page? */
+ size_t guest_pfns = qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS;
+
+ pss->host_page_sending = true;
+ pss->host_page_start = ROUND_DOWN(pss->page, guest_pfns);
+ pss->host_page_end = ROUND_UP(pss->page + 1, guest_pfns);
+}
+
+/*
+ * Whether the page pointed by PSS is within the host page being sent.
+ * Must be called after a previous pss_host_page_prepare().
+ */
+static bool pss_within_range(PageSearchStatus *pss)
+{
+ ram_addr_t ram_addr;
+
+ assert(pss->host_page_sending);
+
+ /* Over host-page boundary? */
+ if (pss->page >= pss->host_page_end) {
+ return false;
+ }
+
+ ram_addr = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS;
+
+ return offset_in_ramblock(pss->block, ram_addr);
+}
+
+static void pss_host_page_finish(PageSearchStatus *pss)
+{
+ pss->host_page_sending = false;
+ /* This is not needed, but just to reset it */
+ pss->host_page_start = pss->host_page_end = 0;
+}
+
/**
* ram_save_host_page: save a whole host page
*
@@ -2479,8 +2536,6 @@ static int ram_save_host_page(RAMState *rs,
PageSearchStatus *pss)
int tmppages, pages = 0;
size_t pagesize_bits =
qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS;
- unsigned long hostpage_boundary =
- QEMU_ALIGN_UP(pss->page + 1, pagesize_bits);
unsigned long start_page = pss->page;
int res;
@@ -2493,6 +2548,9 @@ static int ram_save_host_page(RAMState *rs,
PageSearchStatus *pss)
postcopy_preempt_choose_channel(rs, pss);
}
+ /* Update host page boundary information */
+ pss_host_page_prepare(pss);
+
do {
if (postcopy_needs_preempt(rs, pss)) {
postcopy_do_preempt(rs, pss);
@@ -2530,15 +2588,14 @@ static int ram_save_host_page(RAMState *rs,
PageSearchStatus *pss)
}
if (tmppages < 0) {
+ pss_host_page_finish(pss);
return tmppages;
}
- pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page);
- } while ((pss->page < hostpage_boundary) &&
- offset_in_ramblock(pss->block,
- ((ram_addr_t)pss->page) << TARGET_PAGE_BITS));
- /* The offset we leave with is the min boundary of host page and block */
- pss->page = MIN(pss->page, hostpage_boundary);
+ pss_find_next_dirty(pss);
+ } while (pss_within_range(pss));
+
+ pss_host_page_finish(pss);
/*
* When with postcopy preempt mode, flush the data as soon as possible for
--
2.38.1
- [PATCH v2 28/51] multifd: Create page_size fields into both MultiFD{Recv, Send}Params, (continued)
- [PATCH v2 28/51] multifd: Create page_size fields into both MultiFD{Recv, Send}Params, Juan Quintela, 2022/12/05
- [PATCH v2 29/51] multifd: Create page_count fields into both MultiFD{Recv, Send}Params, Juan Quintela, 2022/12/05
- [PATCH v2 30/51] migration: Export ram_transferred_ram(), Juan Quintela, 2022/12/05
- [PATCH v2 31/51] migration: Export ram_release_page(), Juan Quintela, 2022/12/05
- Re: [PATCH v2 00/51] migration patches for VFIO, Juan Quintela, 2022/12/05
- [PATCH v2 32/51] migration: Take bitmap mutex when completing ram migration, Juan Quintela, 2022/12/05
- [PATCH v2 33/51] migration: Add postcopy_preempt_active(), Juan Quintela, 2022/12/05
- [PATCH v2 34/51] migration: Cleanup xbzrle zero page cache update logic, Juan Quintela, 2022/12/05
- [PATCH v2 36/51] migration: Remove RAMState.f references in compression code, Juan Quintela, 2022/12/05
- [PATCH v2 35/51] migration: Trivial cleanup save_page_header() on same block check, Juan Quintela, 2022/12/05
- [PATCH v2 39/51] migration: Teach PSS about host page,
Juan Quintela <=
- [PATCH v2 37/51] migration: Yield bitmap_mutex properly when sending/sleeping, Juan Quintela, 2022/12/05
- [PATCH v2 38/51] migration: Use atomic ops properly for page accountings, Juan Quintela, 2022/12/05
- [PATCH v2 40/51] migration: Introduce pss_channel, Juan Quintela, 2022/12/05
- [PATCH v2 41/51] migration: Add pss_init(), Juan Quintela, 2022/12/05
- [PATCH v2 42/51] migration: Make PageSearchStatus part of RAMState, Juan Quintela, 2022/12/05
- [PATCH v2 43/51] migration: Move last_sent_block into PageSearchStatus, Juan Quintela, 2022/12/05
- [PATCH v2 44/51] migration: Send requested page directly in rp-return thread, Juan Quintela, 2022/12/05
- [PATCH v2 45/51] migration: Remove old preempt code around state maintainance, Juan Quintela, 2022/12/05
- [PATCH v2 46/51] migration: Drop rs->f, Juan Quintela, 2022/12/05
- [PATCH v2 47/51] migration: Remove res_compatible parameter, Juan Quintela, 2022/12/05