From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O527M-0007YO-Mq for qemu-devel@nongnu.org; Thu, 22 Apr 2010 15:31:20 -0400 Received: from [140.186.70.92] (port=39336 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O527I-0007XL-Is for qemu-devel@nongnu.org; Thu, 22 Apr 2010 15:31:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O527E-0006gQ-Rs for qemu-devel@nongnu.org; Thu, 22 Apr 2010 15:31:14 -0400 Received: from e3.ny.us.ibm.com ([32.97.182.143]:34102) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O527E-0006gK-Ng for qemu-devel@nongnu.org; Thu, 22 Apr 2010 15:31:12 -0400 Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by e3.ny.us.ibm.com (8.14.3/8.13.1) with ESMTP id o3MJIs15018989 for ; Thu, 22 Apr 2010 15:18:54 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o3MJV2GB1339556 for ; Thu, 22 Apr 2010 15:31:03 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o3MJV2no003359 for ; Thu, 22 Apr 2010 15:31:02 -0400 Message-ID: <4BD0A3F4.5050708@linux.vnet.ibm.com> Date: Thu, 22 Apr 2010 14:31:00 -0500 From: Anthony Liguori MIME-Version: 1.0 References: <1271829445-5328-1-git-send-email-tamura.yoshiaki@lab.ntt.co.jp> <1271829445-5328-9-git-send-email-tamura.yoshiaki@lab.ntt.co.jp> In-Reply-To: <1271829445-5328-9-git-send-email-tamura.yoshiaki@lab.ntt.co.jp> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] Re: [RFC PATCH 08/20] Introduce RAMSaveIO and use cpu_physical_memory_get_dirty_range() to check multiple dirty pages. List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Yoshiaki Tamura Cc: ohmura.kei@lab.ntt.co.jp, kvm@vger.kernel.org, mtosatti@redhat.com, Anthony Liguori , qemu-devel@nongnu.org, yoshikawa.takuya@oss.ntt.co.jp, avi@redhat.com On 04/21/2010 12:57 AM, Yoshiaki Tamura wrote: > Introduce RAMSaveIO to use writev for saving ram blocks, and modifies > ram_save_block() and ram_save_remaining() to use > cpu_physical_memory_get_dirty_range() to check multiple dirty and > non-dirty pages at once. > > Signed-off-by: Yoshiaki Tamura > Signed-off-by: OHMURA Kei > Perf data? Regards, Anthony Liguori > --- > vl.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- > 1 files changed, 197 insertions(+), 24 deletions(-) > > diff --git a/vl.c b/vl.c > index 729c955..9c3dc4c 100644 > --- a/vl.c > +++ b/vl.c > @@ -2774,12 +2774,167 @@ static int is_dup_page(uint8_t *page, uint8_t ch) > return 1; > } > > -static int ram_save_block(QEMUFile *f) > +typedef struct RAMSaveIO RAMSaveIO; > + > +struct RAMSaveIO { > + QEMUFile *f; > + QEMUIOVector *qiov; > + > + uint8_t *ram_store; > + size_t nalloc, nused; > + uint8_t io_mode; > + > + void (*put_buffer)(RAMSaveIO *s, uint8_t *buf, size_t len); > + void (*put_byte)(RAMSaveIO *s, int v); > + void (*put_be64)(RAMSaveIO *s, uint64_t v); > + > +}; > + > +static inline void ram_saveio_flush(RAMSaveIO *s, int prepare) > +{ > + qemu_put_vector(s->f, s->qiov); > + if (prepare) > + qemu_put_vector_prepare(s->f); > + > + /* reset stored data */ > + qemu_iovec_reset(s->qiov); > + s->nused = 0; > +} > + > +static inline void ram_saveio_put_buffer(RAMSaveIO *s, uint8_t *buf, size_t len) > +{ > + s->put_buffer(s, buf, len); > +} > + > +static inline void ram_saveio_put_byte(RAMSaveIO *s, int v) > +{ > + s->put_byte(s, v); > +} > + > +static inline void ram_saveio_put_be64(RAMSaveIO *s, uint64_t v) > +{ > + s->put_be64(s, v); > +} > + > +static inline void ram_saveio_set_error(RAMSaveIO *s) > +{ > + qemu_file_set_error(s->f); > +} > + > +static void ram_saveio_put_buffer_vector(RAMSaveIO *s, uint8_t *buf, size_t len) > +{ > + qemu_iovec_add(s->qiov, buf, len); > +} > + > +static void ram_saveio_put_buffer_direct(RAMSaveIO *s, uint8_t *buf, size_t len) > +{ > + qemu_put_buffer(s->f, buf, len); > +} > + > +static void ram_saveio_put_byte_vector(RAMSaveIO *s, int v) > +{ > + uint8_t *to_save; > + > + if (s->nalloc - s->nused< sizeof(int)) > + ram_saveio_flush(s, 1); > + > + to_save =&s->ram_store[s->nused]; > + to_save[0] = v& 0xff; > + s->nused++; > + > + qemu_iovec_add(s->qiov, to_save, 1); > +} > + > +static void ram_saveio_put_byte_direct(RAMSaveIO *s, int v) > +{ > + qemu_put_byte(s->f, v); > +} > + > +static void ram_saveio_put_be64_vector(RAMSaveIO *s, uint64_t v) > +{ > + uint8_t *to_save; > + > + if (s->nalloc - s->nused< sizeof(uint64_t)) > + ram_saveio_flush(s, 1); > + > + to_save =&s->ram_store[s->nused]; > + to_save[0] = (v>> 56)& 0xff; > + to_save[1] = (v>> 48)& 0xff; > + to_save[2] = (v>> 40)& 0xff; > + to_save[3] = (v>> 32)& 0xff; > + to_save[4] = (v>> 24)& 0xff; > + to_save[5] = (v>> 16)& 0xff; > + to_save[6] = (v>> 8)& 0xff; > + to_save[7] = (v>> 0)& 0xff; > + s->nused += sizeof(uint64_t); > + > + qemu_iovec_add(s->qiov, to_save, sizeof(uint64_t)); > +} > + > +static void ram_saveio_put_be64_direct(RAMSaveIO *s, uint64_t v) > +{ > + > + qemu_put_be64(s->f, v); > +} > + > +static RAMSaveIO *ram_saveio_new(QEMUFile *f, size_t max_store) > +{ > + RAMSaveIO *s; > + > + s = qemu_mallocz(sizeof(*s)); > + > + if (qemu_file_get_rate_limit(f) == 0) {/* non buffer mode */ > + /* When QEMUFile don't have get_rate limit, > + * qemu_file_get_rate_limit will return 0. > + * However, we believe that all kinds of QEMUFile > + * except non-block mode has rate limit function. > + */ > + s->io_mode = 1; > + s->ram_store = qemu_mallocz(max_store); > + s->nalloc = max_store; > + s->nused = 0; > + > + s->qiov = qemu_mallocz(sizeof(*s->qiov)); > + qemu_iovec_init(s->qiov, max_store); > + > + s->put_buffer = ram_saveio_put_buffer_vector; > + s->put_byte = ram_saveio_put_byte_vector; > + s->put_be64 = ram_saveio_put_be64_vector; > + > + qemu_put_vector_prepare(f); > + } else { > + s->io_mode = 0; > + s->put_buffer = ram_saveio_put_buffer_direct; > + s->put_byte = ram_saveio_put_byte_direct; > + s->put_be64 = ram_saveio_put_be64_direct; > + } > + > + s->f = f; > + > + return s; > +} > + > +static void ram_saveio_destroy(RAMSaveIO *s) > +{ > + if (s->qiov != NULL) { /* means using put_vector */ > + ram_saveio_flush(s, 0); > + qemu_iovec_destroy(s->qiov); > + qemu_free(s->qiov); > + qemu_free(s->ram_store); > + } > + qemu_free(s); > +} > + > +/* > + * RAMSaveIO will manage I/O. > + */ > +static int ram_save_block(RAMSaveIO *s) > { > static ram_addr_t current_addr = 0; > ram_addr_t saved_addr = current_addr; > ram_addr_t addr = 0; > - int found = 0; > + ram_addr_t dirty_rams[HOST_LONG_BITS]; > + int i, found = 0; > > while (addr< last_ram_offset) { > if (kvm_enabled()&& current_addr == 0) { > @@ -2787,32 +2942,38 @@ static int ram_save_block(QEMUFile *f) > r = kvm_update_dirty_pages_log(); > if (r) { > fprintf(stderr, "%s: update dirty pages log failed %d\n", __FUNCTION__, r); > - qemu_file_set_error(f); > + ram_saveio_set_error(s); > return 0; > } > } > - if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) { > + if ((found = cpu_physical_memory_get_dirty_range( > + current_addr, last_ram_offset, dirty_rams, HOST_LONG_BITS, > + MIGRATION_DIRTY_FLAG))) { > uint8_t *p; > > - cpu_physical_memory_reset_dirty(current_addr, > - current_addr + TARGET_PAGE_SIZE, > - MIGRATION_DIRTY_FLAG); > + for (i = 0; i< found; i++) { > + ram_addr_t page_addr = dirty_rams[i]; > + cpu_physical_memory_reset_dirty(page_addr, > + page_addr + TARGET_PAGE_SIZE, > + MIGRATION_DIRTY_FLAG); > > - p = qemu_get_ram_ptr(current_addr); > + p = qemu_get_ram_ptr(page_addr); > > - if (is_dup_page(p, *p)) { > - qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS); > - qemu_put_byte(f, *p); > - } else { > - qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE); > - qemu_put_buffer(f, p, TARGET_PAGE_SIZE); > + if (is_dup_page(p, *p)) { > + ram_saveio_put_be64(s, > + (page_addr) | RAM_SAVE_FLAG_COMPRESS); > + ram_saveio_put_byte(s, *p); > + } else { > + ram_saveio_put_be64(s, (page_addr) | RAM_SAVE_FLAG_PAGE); > + ram_saveio_put_buffer(s, p, TARGET_PAGE_SIZE); > + } > } > > - found = 1; > break; > + } else { > + addr += dirty_rams[0]; > + current_addr = (saved_addr + addr) % last_ram_offset; > } > - addr += TARGET_PAGE_SIZE; > - current_addr = (saved_addr + addr) % last_ram_offset; > } > > return found; > @@ -2822,12 +2983,19 @@ static uint64_t bytes_transferred; > > static ram_addr_t ram_save_remaining(void) > { > - ram_addr_t addr; > + ram_addr_t addr = 0; > ram_addr_t count = 0; > + ram_addr_t dirty_rams[HOST_LONG_BITS]; > + int found = 0; > > - for (addr = 0; addr< last_ram_offset; addr += TARGET_PAGE_SIZE) { > - if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) > - count++; > + while (addr< last_ram_offset) { > + if ((found = cpu_physical_memory_get_dirty_range(addr, last_ram_offset, > + dirty_rams, HOST_LONG_BITS, MIGRATION_DIRTY_FLAG))) { > + count += found; > + addr = dirty_rams[found - 1] + TARGET_PAGE_SIZE; > + } else { > + addr += dirty_rams[0]; > + } > } > > return count; > @@ -2854,6 +3022,7 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) > uint64_t bytes_transferred_last; > double bwidth = 0; > uint64_t expected_time = 0; > + RAMSaveIO *s; > > if (stage< 0) { > cpu_physical_memory_set_dirty_tracking(0); > @@ -2883,10 +3052,12 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) > bytes_transferred_last = bytes_transferred; > bwidth = qemu_get_clock_ns(rt_clock); > > - while (!qemu_file_rate_limit(f)) { > + s = ram_saveio_new(f, IOV_MAX); > + > + while (!qemu_file_rate_limit(f)) { > int ret; > > - ret = ram_save_block(f); > + ret = ram_save_block(s); > bytes_transferred += ret * TARGET_PAGE_SIZE; > if (ret == 0) /* no more blocks */ > break; > @@ -2903,12 +3074,14 @@ static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) > /* try transferring iterative blocks of memory */ > if (stage == 3) { > /* flush all remaining blocks regardless of rate limiting */ > - while (ram_save_block(f) != 0) { > + while (ram_save_block(s) != 0) { > bytes_transferred += TARGET_PAGE_SIZE; > } > cpu_physical_memory_set_dirty_tracking(0); > } > > + ram_saveio_destroy(s); > + > qemu_put_be64(f, RAM_SAVE_FLAG_EOS); > > expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; >