[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v6 36/47] Page request: Consume pages off the post-c
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[Qemu-devel] [PATCH v6 36/47] Page request: Consume pages off the post-copy queue |
Date: |
Tue, 14 Apr 2015 18:04:02 +0100 |
From: "Dr. David Alan Gilbert" <address@hidden>
When transmitting RAM pages, consume pages that have been queued by
MIG_RPCOMM_REQPAGE commands and send them ahead of normal page scanning.
Note:
a) After a queued page the linear walk carries on from after the
unqueued page; there is a reasonable chance that the destination
was about to ask for other closeby pages anyway.
b) We have to be careful of any assumptions that the page walking
code makes, in particular it does some short cuts on its first linear
walk that break as soon as we do a queued page.
Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
arch_init.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++----------
trace-events | 2 +
2 files changed, 132 insertions(+), 26 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 48403f3..c96c4c1 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -312,6 +312,7 @@ static RAMBlock *last_seen_block;
/* This is the last block from where we have sent data */
static RAMBlock *last_sent_block;
static ram_addr_t last_offset;
+static bool last_was_from_queue;
static unsigned long *migration_bitmap;
static uint64_t migration_dirty_pages;
static uint32_t last_version;
@@ -490,6 +491,19 @@ static inline bool migration_bitmap_set_dirty(ram_addr_t
addr)
return ret;
}
+static inline bool migration_bitmap_clear_dirty(ram_addr_t addr)
+{
+ bool ret;
+ int nr = addr >> TARGET_PAGE_BITS;
+
+ ret = test_and_clear_bit(nr, migration_bitmap);
+
+ if (ret) {
+ migration_dirty_pages--;
+ }
+ return ret;
+}
+
static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
{
ram_addr_t addr;
@@ -716,6 +730,40 @@ static int ram_save_page(QEMUFile *f, RAMBlock* block,
ram_addr_t offset,
}
/*
+ * Unqueue a page from the queue fed by postcopy page requests
+ *
+ * Returns: The RAMBlock* to transmit from (or NULL if the queue is empty)
+ * ms: MigrationState in
+ * offset: the byte offset within the RAMBlock for the start of the page
+ * ram_addr_abs: global offset in the dirty/sent bitmaps
+ */
+static RAMBlock *ram_save_unqueue_page(MigrationState *ms, ram_addr_t *offset,
+ ram_addr_t *ram_addr_abs)
+{
+ RAMBlock *result = NULL;
+ qemu_mutex_lock(&ms->src_page_req_mutex);
+ if (!QSIMPLEQ_EMPTY(&ms->src_page_requests)) {
+ struct MigrationSrcPageRequest *entry =
+ QSIMPLEQ_FIRST(&ms->src_page_requests);
+ result = entry->rb;
+ *offset = entry->offset;
+ *ram_addr_abs = (entry->offset + entry->rb->offset) & TARGET_PAGE_MASK;
+
+ if (entry->len > TARGET_PAGE_SIZE) {
+ entry->len -= TARGET_PAGE_SIZE;
+ entry->offset += TARGET_PAGE_SIZE;
+ } else {
+ memory_region_unref(result->mr);
+ QSIMPLEQ_REMOVE_HEAD(&ms->src_page_requests, next_req);
+ g_free(entry);
+ }
+ }
+ qemu_mutex_unlock(&ms->src_page_req_mutex);
+
+ return result;
+}
+
+/*
* Queue the pages for transmission, e.g. a request from postcopy destination
* ms: MigrationStatus in which the queue is held
* rbname: The RAMBlock the request is for - may be NULL (to mean reuse last)
@@ -793,47 +841,102 @@ err:
static int ram_find_and_save_block(QEMUFile *f, bool last_stage,
uint64_t *bytes_transferred)
{
+ MigrationState *ms = migrate_get_current();
RAMBlock *block = last_seen_block;
+ RAMBlock *tmpblock;
ram_addr_t offset = last_offset;
+ ram_addr_t tmpoffset;
bool complete_round = false;
int pages = 0;
- MemoryRegion *mr;
ram_addr_t dirty_ram_abs; /* Address of the start of the dirty page in
ram_addr_t space */
+ unsigned long hps = sysconf(_SC_PAGESIZE);
- if (!block)
+ if (!block) {
block = QLIST_FIRST_RCU(&ram_list.blocks);
+ last_was_from_queue = false;
+ }
- while (true) {
- mr = block->mr;
- offset = migration_bitmap_find_and_reset_dirty(mr, offset,
- &dirty_ram_abs);
- if (complete_round && block == last_seen_block &&
- offset >= last_offset) {
- break;
+ while (true) { /* Until we send a block or run out of stuff to send */
+ tmpblock = NULL;
+
+ /*
+ * Don't break host-page chunks up with queue items
+ * so only unqueue if,
+ * a) The last item came from the queue anyway
+ * b) The last sent item was the last target-page in a host page
+ */
+ if (last_was_from_queue || !last_sent_block ||
+ ((last_offset & (hps - 1)) == (hps - TARGET_PAGE_SIZE))) {
+ tmpblock = ram_save_unqueue_page(ms, &tmpoffset, &dirty_ram_abs);
}
- if (offset >= block->used_length) {
- offset = 0;
- block = QLIST_NEXT_RCU(block, next);
- if (!block) {
- block = QLIST_FIRST_RCU(&ram_list.blocks);
- complete_round = true;
- ram_bulk_stage = false;
+
+ if (tmpblock) {
+ /* We've got a block from the postcopy queue */
+ trace_ram_find_and_save_block_postcopy(tmpblock->idstr,
+ (uint64_t)tmpoffset,
+ (uint64_t)dirty_ram_abs);
+ /*
+ * We're sending this page, and since it's postcopy nothing else
+ * will dirty it, and we must make sure it doesn't get sent again.
+ */
+ if (!migration_bitmap_clear_dirty(dirty_ram_abs)) {
+ trace_ram_find_and_save_block_postcopy_not_dirty(
+ tmpblock->idstr, (uint64_t)tmpoffset,
+ (uint64_t)dirty_ram_abs,
+ test_bit(dirty_ram_abs >> TARGET_PAGE_BITS, ms->sentmap));
+
+ continue;
}
+ /*
+ * As soon as we start servicing pages out of order, then we have
+ * to kill the bulk stage, since the bulk stage assumes
+ * in (migration_bitmap_find_and_reset_dirty) that every page is
+ * dirty, that's no longer true.
+ */
+ ram_bulk_stage = false;
+ /*
+ * We mustn't change block/offset unless it's to a valid one
+ * otherwise we can go down some of the exit cases in the normal
+ * path.
+ */
+ block = tmpblock;
+ offset = tmpoffset;
+ last_was_from_queue = true;
} else {
- pages = ram_save_page(f, block, offset, last_stage,
- bytes_transferred);
-
- /* if page is unmodified, continue to the next */
- if (pages > 0) {
- MigrationState *ms = migrate_get_current();
- if (ms->sentmap) {
- set_bit(dirty_ram_abs >> TARGET_PAGE_BITS, ms->sentmap);
+ MemoryRegion *mr;
+ /* priority queue empty, so just search for something dirty */
+ mr = block->mr;
+ offset = migration_bitmap_find_and_reset_dirty(mr, offset,
+ &dirty_ram_abs);
+ if (complete_round && block == last_seen_block &&
+ offset >= last_offset) {
+ break;
+ }
+ if (offset >= block->used_length) {
+ offset = 0;
+ block = QLIST_NEXT_RCU(block, next);
+ if (!block) {
+ block = QLIST_FIRST_RCU(&ram_list.blocks);
+ complete_round = true;
+ ram_bulk_stage = false;
}
+ continue; /* pick an offset in the new block */
+ }
+ last_was_from_queue = false;
+ }
- last_sent_block = block;
- break;
+ /* We have a page to send, so send it */
+ pages = ram_save_page(f, block, offset, last_stage,
+ bytes_transferred);
+
+ /* if page is unmodified, continue to the next */
+ if (pages > 0) {
+ if (ms->sentmap) {
+ set_bit(dirty_ram_abs >> TARGET_PAGE_BITS, ms->sentmap);
}
+
+ break;
}
}
@@ -929,6 +1032,7 @@ static void reset_ram_globals(void)
last_offset = 0;
last_version = ram_list.version;
ram_bulk_stage = true;
+ last_was_from_queue = false;
}
#define MAX_WAIT 50 /* ms, half buffered_file limit */
diff --git a/trace-events b/trace-events
index 3792d2e..c4b92ce 100644
--- a/trace-events
+++ b/trace-events
@@ -1219,6 +1219,8 @@ qemu_file_fclose(void) ""
migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64""
migration_throttle(void) ""
+ram_find_and_save_block_postcopy(const char *block_name, uint64_t tmp_offset,
uint64_t ram_addr) "%s/%" PRIx64 " ram_addr=%" PRIx64
+ram_find_and_save_block_postcopy_not_dirty(const char *block_name, uint64_t
tmp_offset, uint64_t ram_addr, int sent) "%s/%" PRIx64 " ram_addr=%" PRIx64 "
(sent=%d)"
ram_postcopy_send_discard_bitmap(void) ""
ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start:
%zx len: %zx"
--
2.1.0
- [Qemu-devel] [PATCH v6 25/47] postcopy: OS support test, (continued)
- [Qemu-devel] [PATCH v6 25/47] postcopy: OS support test, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 26/47] migrate_start_postcopy: Command to trigger transition to postcopy, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 21/47] Add wrappers and handlers for sending/receiving the postcopy-ram migration messages., Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 27/47] MIGRATION_STATUS_POSTCOPY_ACTIVE: Add new migration state, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 28/47] Add qemu_savevm_state_complete_postcopy, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 32/47] Postcopy: Postcopy startup in migration thread, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 30/47] postcopy: Incoming initialisation, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 33/47] Postcopy end in migration_thread, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 29/47] Postcopy: Maintain sentmap and calculate discard, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 35/47] Page request: Process incoming page request, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 36/47] Page request: Consume pages off the post-copy queue,
Dr. David Alan Gilbert (git) <=
- [Qemu-devel] [PATCH v6 34/47] Page request: Add MIG_RP_MSG_REQ_PAGES reverse command, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 38/47] Postcopy: Use helpers to map pages during migration, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 40/47] Don't sync dirty bitmaps in postcopy, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 39/47] qemu_ram_block_from_host, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 37/47] postcopy_ram.c: place_page and helpers, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 41/47] Host page!=target page: Cleanup bitmaps, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 43/47] Start up a postcopy/listener thread ready for incoming page data, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 31/47] postcopy: ram_enable_notify to switch on userfault, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 42/47] Postcopy; Handle userfault requests, Dr. David Alan Gilbert (git), 2015/04/14
- [Qemu-devel] [PATCH v6 46/47] Disable mlock around incoming postcopy, Dr. David Alan Gilbert (git), 2015/04/14