[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 22/30] migration: Teach PSS about host page
From: |
Juan Quintela |
Subject: |
[PULL 22/30] migration: Teach PSS about host page |
Date: |
Tue, 15 Nov 2022 16:35:06 +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 25fd3cf7dc..b71edf1f26 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -509,6 +509,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;
@@ -886,26 +891,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,
@@ -1591,7 +1608,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) {
/*
@@ -2480,6 +2499,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
*
@@ -2507,8 +2564,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;
@@ -2521,6 +2576,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);
@@ -2558,15 +2616,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
- [PULL 09/30] Unit test code and benchmark code, (continued)
- [PULL 09/30] Unit test code and benchmark code, Juan Quintela, 2022/11/15
- [PULL 06/30] migration: Export ram_transferred_ram(), Juan Quintela, 2022/11/15
- [PULL 12/30] migration: Disallow postcopy preempt to be used with compress, Juan Quintela, 2022/11/15
- [PULL 13/30] migration: Use non-atomic ops for clear log bitmap, Juan Quintela, 2022/11/15
- [PULL 15/30] migration: Take bitmap mutex when completing ram migration, Juan Quintela, 2022/11/15
- [PULL 16/30] migration: Add postcopy_preempt_active(), Juan Quintela, 2022/11/15
- [PULL 11/30] migration: Fix race on qemu_file_shutdown(), Juan Quintela, 2022/11/15
- [PULL 14/30] migration: Disable multifd explicitly with compression, Juan Quintela, 2022/11/15
- [PULL 17/30] migration: Cleanup xbzrle zero page cache update logic, Juan Quintela, 2022/11/15
- [PULL 21/30] migration: Use atomic ops properly for page accountings, Juan Quintela, 2022/11/15
- [PULL 22/30] migration: Teach PSS about host page,
Juan Quintela <=
- [PULL 25/30] migration: Make PageSearchStatus part of RAMState, Juan Quintela, 2022/11/15
- [PULL 18/30] migration: Trivial cleanup save_page_header() on same block check, Juan Quintela, 2022/11/15
- [PULL 20/30] migration: Yield bitmap_mutex properly when sending/sleeping, Juan Quintela, 2022/11/15
- [PULL 23/30] migration: Introduce pss_channel, Juan Quintela, 2022/11/15
- [PULL 19/30] migration: Remove RAMState.f references in compression code, Juan Quintela, 2022/11/15
- [PULL 24/30] migration: Add pss_init(), Juan Quintela, 2022/11/15
- [PULL 27/30] migration: Send requested page directly in rp-return thread, Juan Quintela, 2022/11/15
- [PULL 29/30] migration: Drop rs->f, Juan Quintela, 2022/11/15
- [PULL 26/30] migration: Move last_sent_block into PageSearchStatus, Juan Quintela, 2022/11/15
- [PULL 30/30] migration: Block migration comment or code is wrong, Juan Quintela, 2022/11/15