* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-24 18:19 [Qemu-devel] [PATCH 00/11] Migration next v5 Juan Quintela
@ 2012-07-24 18:19 ` Juan Quintela
0 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-07-24 18:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 21 +++++++++++++++++++++
migration.c | 36 +++++++++++++++++++++++++++++-------
migration.h | 4 ++++
qapi-schema.json | 27 +++++++++++++++++++++++++--
qmp-commands.hx | 33 ++++++++++++++++++++++++++++++++-
6 files changed, 139 insertions(+), 10 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 12afc46..f89908f 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -209,7 +209,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -239,6 +243,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -267,6 +291,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -284,6 +309,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -301,7 +327,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_byte(f, hdr.xh_flags);
qemu_put_be16(f, hdr.xh_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
+ acct_info.xbzrle_pages++;
bytes_sent = encoded_len + sizeof(hdr);
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index e0f520d..c141f90 100644
--- a/hmp.c
+++ b/hmp.c
@@ -168,6 +168,27 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ if (info->xbzrle_cache->has_xbzrle_bytes) {
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->xbzrle_bytes >> 10);
+ }
+ if (info->xbzrle_cache->has_xbzrle_pages) {
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->xbzrle_pages);
+ }
+ if (info->xbzrle_cache->has_xbzrle_cache_miss) {
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_cache_miss);
+ }
+ if (info->xbzrle_cache->has_xbzrle_overflow) {
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_overflow);
+ }
+ }
+
qapi_free_MigrationInfo(info);
}
diff --git a/migration.c b/migration.c
index cae444c..4be047a 100644
--- a/migration.c
+++ b/migration.c
@@ -133,6 +133,24 @@ static void get_capabilities(MigrationState *s, MigrationInfo *info)
info->capabilities->next = NULL;
}
}
+
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->has_xbzrle_bytes = true;
+ info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->has_xbzrle_pages = true;
+ info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->has_xbzrle_cache_miss = true;
+ info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->has_xbzrle_overflow = true;
+ info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -142,6 +160,14 @@ MigrationInfo *qmp_query_migrate(Error **errp)
case MIG_STATE_SETUP:
/* no migration has ever happened; show enabled capabilities */
get_capabilities(s, info);
+
+ /* display xbzrle cache size */
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ }
+
break;
case MIG_STATE_ACTIVE:
get_capabilities(s, info);
@@ -166,17 +192,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
get_capabilities(s, info);
- info->has_ram = true;
- info->ram = g_malloc0(sizeof(*info->ram));
- info->ram->transferred = ram_bytes_transferred();
- info->ram->remaining = ram_bytes_remaining();
- info->ram->total = ram_bytes_total();
- info->ram->duplicate = dup_mig_pages_transferred();
- info->ram->normal = norm_mig_pages_transferred();
+ get_xbzrle_cache_stats(info);
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index 8676c1d..a4528f9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -273,6 +273,26 @@
{ 'type': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
'total_time': 'int', '*duplicate': 'int', '*normal': 'int' } }
+##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache_size: XBZRLE cache size
+#
+# @xbzrle_bytes: amount of bytes already transferred to the target VM
+#
+# @xbzrle_pages: amount of pages transferred to the target VM
+#
+# @xbzrle_cache_miss: number of cache miss
+#
+# @xbzrle_overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
+ '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
##
# @MigrationInfo
@@ -295,13 +315,16 @@
# @capabilities: #optional a list describing all the migration capabilities
# state (since 1.2)
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
'*disk': 'MigrationStats',
- '*capabilities': ['MigrationCapabilityStatus']} }
-
+ '*capabilities': ['MigrationCapabilityStatus'],
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
#
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9a4bff0..3518e64 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2108,10 +2108,17 @@ The main json-object contains the following:
- "total": total (json-int)
- "capabilities": migration capabilities state
- "xbzrle" : XBZRLE state (json-bool)
+- "cache": only present if "status" and XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "xbzrle-bytes": total XBZRLE bytes transferred
+ - "xbzrle-pages": number of XBZRLE compressed pages
+ - "cache-miss": number of cache misses
+ - "overflow": number of XBZRLE overflows
+
Examples:
1. Before the first migration
-
-> { "execute": "query-migrate" }
<- { "return": {
"capabilities" : [ { "capability" : "xbzrle", "state" : false } ]
@@ -2172,6 +2179,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal" : 3333
+ },
+ "cache":{
+ "cache-size": 1024
+ "xbzrle-transferred":20971520,
+ "xbzrle-pages":2444343,
+ "xbzrle-cache-miss":2244,
+ "xbzrle-overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.10.4
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-25 14:50 [Qemu-devel] [PATCH 00/11] Migration next v6 Orit Wasserman
@ 2012-07-25 14:50 ` Orit Wasserman
2012-07-26 22:48 ` Eric Blake
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-07-25 14:50 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, aliguori, quintela, Petter Svard, stefanha, mdroth,
Benoit Hudzia, lcapitulino, blauwirbel, Orit Wasserman,
chegu_vinod, avi, Aidan Shribman, pbonzini, eblake
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 21 +++++++++++++++++++++
migration.c | 28 ++++++++++++++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 26 +++++++++++++++++++++++++-
qmp-commands.hx | 32 +++++++++++++++++++++++++++++++-
6 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index e50cdf2..f484bd5 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -209,7 +209,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -239,6 +243,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -267,6 +291,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -284,6 +309,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -301,7 +327,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_byte(f, hdr.xh_flags);
qemu_put_be16(f, hdr.xh_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
+ acct_info.xbzrle_pages++;
bytes_sent = encoded_len + sizeof(hdr);
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index 9770d7b..383d5b1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ if (info->xbzrle_cache->has_xbzrle_bytes) {
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->xbzrle_bytes >> 10);
+ }
+ if (info->xbzrle_cache->has_xbzrle_pages) {
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->xbzrle_pages);
+ }
+ if (info->xbzrle_cache->has_xbzrle_cache_miss) {
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_cache_miss);
+ }
+ if (info->xbzrle_cache->has_xbzrle_overflow) {
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_overflow);
+ }
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationParameters(params);
}
diff --git a/migration.c b/migration.c
index 4dc99ba..fb802bc 100644
--- a/migration.c
+++ b/migration.c
@@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
return params;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->has_xbzrle_bytes = true;
+ info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->has_xbzrle_pages = true;
+ info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->has_xbzrle_cache_miss = true;
+ info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->has_xbzrle_overflow = true;
+ info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
switch (s->state) {
case MIG_STATE_SETUP:
/* no migration has happened ever */
+
+ /* display xbzrle cache size */
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ }
break;
case MIG_STATE_ACTIVE:
info->has_status = true;
@@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index 88b7b56..9418f23 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -273,6 +273,26 @@
{ 'type': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
'total_time': 'int', '*duplicate': 'int', '*normal': 'int' } }
+##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache_size: XBZRLE cache size
+#
+# @xbzrle_bytes: amount of bytes already transferred to the target VM
+#
+# @xbzrle_pages: amount of pages transferred to the target VM
+#
+# @xbzrle_cache_miss: number of cache miss
+#
+# @xbzrle_overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
+ '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
##
# @MigrationInfo
@@ -292,11 +312,15 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d0e8878..946d921 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2106,10 +2106,16 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
+- "cache": only present if "status" and XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "xbzrle-bytes": total XBZRLE bytes transferred
+ - "xbzrle-pages": number of XBZRLE compressed pages
+ - "cache-miss": number of cache misses
+ - "overflow": number of XBZRLE overflows
Examples:
1. Before the first migration
-
-> { "execute": "query-migrate" }
<- { "return": {} }
@@ -2164,6 +2170,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal" : 3333
+ },
+ "cache":{
+ "cache-size": 1024
+ "xbzrle-transferred":20971520,
+ "xbzrle-pages":2444343,
+ "xbzrle-cache-miss":2244,
+ "xbzrle-overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-25 14:50 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
@ 2012-07-26 22:48 ` Eric Blake
2012-07-29 7:10 ` Orit Wasserman
0 siblings, 1 reply; 31+ messages in thread
From: Eric Blake @ 2012-07-26 22:48 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel, mdroth,
blauwirbel, Petter Svard, Benoit Hudzia, avi, Aidan Shribman,
pbonzini, lcapitulino, chegu_vinod
[-- Attachment #1: Type: text/plain, Size: 3414 bytes --]
On 07/25/2012 08:50 AM, Orit Wasserman wrote:
> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> Signed-off-by: Petter Svard <petters@cs.umu.se>
> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
> +++ b/qapi-schema.json
> @@ -273,6 +273,26 @@
> { 'type': 'MigrationStats',
> 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
> 'total_time': 'int', '*duplicate': 'int', '*normal': 'int' } }
> +##
> +# @XBZRLECacheStats
> +#
> +# Detailed XBZRLE migration cache statistics
> +#
> +# @cache_size: XBZRLE cache size
s/cache_size/cache-size/, and so on throughout this struct (it is new,
so it should use '-' instead of '_'); especially since you already made
that change in the JSON itself.
> +#
> +# @xbzrle_bytes: amount of bytes already transferred to the target VM
> +#
> +# @xbzrle_pages: amount of pages transferred to the target VM
> +#
> +# @xbzrle_cache_miss: number of cache miss
> +#
> +# @xbzrle_overflow: number of overflows
> +#
> +# Since: 1.2
> +##
> +{ 'type': 'XBZRLECacheStats',
> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
Why are you marking four of the five fields optional here, but not in
the text above? I don't think any of them should be optional.
>
> ##
> # @MigrationInfo
> @@ -292,11 +312,15 @@
> # status, only returned if status is 'active' and it is a block
> # migration
> #
> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
> +# migration statistics (since 1.2)
Now _this_ field is indeed optional - it should appear in the output
only when xbzrle is enabled. You may want to mention that in the
description (just like the previous field mentions that it was only
available for a block migration).
> +++ b/qmp-commands.hx
> @@ -2106,10 +2106,16 @@ The main json-object contains the following:
> - "transferred": amount transferred (json-int)
> - "remaining": amount remaining (json-int)
> - "total": total (json-int)
> +- "cache": only present if "status" and XBZRLE is active.
Naming mismatch; you named it 'xbzrle-cache' above.
> + It is a json-object with the following XBZRLE information:
> + - "cache-size": XBZRLE cache size
> + - "xbzrle-bytes": total XBZRLE bytes transferred
Just so I'm clear, is xbzrle-bytes is the number of compressed bytes
sent over the wire, or the number of uncompressed bytes? Likewise, at
the top level, is 'total' the number of bytes sent over the wire, or the
number of bytes after decompression?
That is, if I compare this field against 'total', which field will
always be bigger? Knowing this will let me compute my percentage of
savings due to compressed pages.
> + - "xbzrle-pages": number of XBZRLE compressed pages
> + - "cache-miss": number of cache misses
> + - "overflow": number of XBZRLE overflows
> Examples:
>
> 1. Before the first migration
> -
> -> { "execute": "query-migrate" }
Spurious whitespace change.
--
Eric Blake eblake@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 620 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-26 22:48 ` Eric Blake
@ 2012-07-29 7:10 ` Orit Wasserman
0 siblings, 0 replies; 31+ messages in thread
From: Orit Wasserman @ 2012-07-29 7:10 UTC (permalink / raw)
To: Eric Blake
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel, mdroth,
blauwirbel, Petter Svard, Benoit Hudzia, avi, Aidan Shribman,
pbonzini, lcapitulino, chegu_vinod
On 07/27/2012 01:48 AM, Eric Blake wrote:
> On 07/25/2012 08:50 AM, Orit Wasserman wrote:
>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
>> Signed-off-by: Petter Svard <petters@cs.umu.se>
>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>> +++ b/qapi-schema.json
>> @@ -273,6 +273,26 @@
>> { 'type': 'MigrationStats',
>> 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
>> 'total_time': 'int', '*duplicate': 'int', '*normal': 'int' } }
>> +##
>> +# @XBZRLECacheStats
>> +#
>> +# Detailed XBZRLE migration cache statistics
>> +#
>> +# @cache_size: XBZRLE cache size
>
> s/cache_size/cache-size/, and so on throughout this struct (it is new,
> so it should use '-' instead of '_'); especially since you already made
> that change in the JSON itself.
>
ok
>> +#
>> +# @xbzrle_bytes: amount of bytes already transferred to the target VM
>> +#
>> +# @xbzrle_pages: amount of pages transferred to the target VM
>> +#
>> +# @xbzrle_cache_miss: number of cache miss
>> +#
>> +# @xbzrle_overflow: number of overflows
>> +#
>> +# Since: 1.2
>> +##
>> +{ 'type': 'XBZRLECacheStats',
>> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
>> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
>
> Why are you marking four of the five fields optional here, but not in
> the text above? I don't think any of them should be optional.
If the migration is not active only cache size will be available (requested by Luiz).
I will add it to the comment.
>
>>
>> ##
>> # @MigrationInfo
>> @@ -292,11 +312,15 @@
>> # status, only returned if status is 'active' and it is a block
>> # migration
>> #
>> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
>> +# migration statistics (since 1.2)
>
> Now _this_ field is indeed optional - it should appear in the output
> only when xbzrle is enabled. You may want to mention that in the
> description (just like the previous field mentions that it was only
> available for a block migration).
ok
>
>> +++ b/qmp-commands.hx
>> @@ -2106,10 +2106,16 @@ The main json-object contains the following:
>> - "transferred": amount transferred (json-int)
>> - "remaining": amount remaining (json-int)
>> - "total": total (json-int)
>> +- "cache": only present if "status" and XBZRLE is active.
>
> Naming mismatch; you named it 'xbzrle-cache' above.
ok
>
>> + It is a json-object with the following XBZRLE information:
>> + - "cache-size": XBZRLE cache size
>> + - "xbzrle-bytes": total XBZRLE bytes transferred
>
> Just so I'm clear, is xbzrle-bytes is the number of compressed bytes
> sent over the wire, or the number of uncompressed bytes? Likewise, at
> the top level, is 'total' the number of bytes sent over the wire, or the
> number of bytes after decompression?
xbzrle-bytes are the compressed bytes sent on the wire.
total is the total bytes sent on the wire (including xbzrle_bytes and duplicates ...).
>
> That is, if I compare this field against 'total', which field will
> always be bigger? Knowing this will let me compute my percentage of
> savings due to compressed pages.
total will be always bigger.
>
>> + - "xbzrle-pages": number of XBZRLE compressed pages
>> + - "cache-miss": number of cache misses
>> + - "overflow": number of XBZRLE overflows
>> Examples:
>>
>> 1. Before the first migration
>> -
>> -> { "execute": "query-migrate" }
>
> Spurious whitespace change.
>
Thanks,
Orit
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-29 9:42 [Qemu-devel] [PATCH 00/11] Migration next v7 Orit Wasserman
@ 2012-07-29 9:43 ` Orit Wasserman
2012-07-30 19:37 ` Luiz Capitulino
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-07-29 9:43 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, aliguori, quintela, Petter Svard, stefanha, mdroth,
Benoit Hudzia, lcapitulino, blauwirbel, Orit Wasserman,
chegu_vinod, avi, Aidan Shribman, pbonzini, eblake
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 21 +++++++++++++++++++++
migration.c | 28 ++++++++++++++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
6 files changed, 147 insertions(+), 1 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 7f12317..9833d54 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index 9770d7b..383d5b1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ if (info->xbzrle_cache->has_xbzrle_bytes) {
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->xbzrle_bytes >> 10);
+ }
+ if (info->xbzrle_cache->has_xbzrle_pages) {
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->xbzrle_pages);
+ }
+ if (info->xbzrle_cache->has_xbzrle_cache_miss) {
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_cache_miss);
+ }
+ if (info->xbzrle_cache->has_xbzrle_overflow) {
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_overflow);
+ }
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationParameters(params);
}
diff --git a/migration.c b/migration.c
index 4dc99ba..fb802bc 100644
--- a/migration.c
+++ b/migration.c
@@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
return params;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->has_xbzrle_bytes = true;
+ info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->has_xbzrle_pages = true;
+ info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->has_xbzrle_cache_miss = true;
+ info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->has_xbzrle_overflow = true;
+ info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
switch (s->state) {
case MIG_STATE_SETUP:
/* no migration has happened ever */
+
+ /* display xbzrle cache size */
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ }
break;
case MIG_STATE_ACTIVE:
info->has_status = true;
@@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index a936714..91dee72 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -275,6 +275,31 @@
'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
+# only returned when migration is active or completed
+#
+# @xbzrle-pages: @optional, amount of pages transferred to the target VM
+# only returned when migration is active or completed
+#
+# @xbzrle-cache-miss: @optional, number of cache miss
+# only returned when migration is active or completed
+#
+# @xbzrle-overflow: @optional, number of overflows
+# only returned when migration is active or completed
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
+ '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
+
+##
# @MigrationInfo
#
# Information about current migration process.
@@ -292,11 +317,16 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on
+# (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a5a67eb..0546f42 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2106,6 +2106,17 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
+ status is "active" or "completed"
+ - "xbzrle-pages": number of XBZRLE compressed pages, only present if
+ status is "active" or "completed"
+ - "cache-miss": number of cache misses, only present if
+ status is "active" or "completed"
+ - "overflow": number of XBZRLE overflows, only present if
+ status is "active" or "completed"
Examples:
1. Before the first migration
@@ -2170,6 +2181,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal" : 3333
+ },
+ "cache":{
+ "cache-size": 1024
+ "xbzrle-transferred":20971520,
+ "xbzrle-pages":2444343,
+ "xbzrle-cache-miss":2244,
+ "xbzrle-overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-29 9:43 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
@ 2012-07-30 19:37 ` Luiz Capitulino
2012-07-31 8:31 ` Orit Wasserman
0 siblings, 1 reply; 31+ messages in thread
From: Luiz Capitulino @ 2012-07-30 19:37 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel,
Benoit Hudzia, mdroth, blauwirbel, Petter Svard, chegu_vinod, avi,
Aidan Shribman, pbonzini, eblake
On Sun, 29 Jul 2012 12:43:02 +0300
Orit Wasserman <owasserm@redhat.com> wrote:
> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> Signed-off-by: Petter Svard <petters@cs.umu.se>
> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
> arch_init.c | 28 ++++++++++++++++++++++++++++
> hmp.c | 21 +++++++++++++++++++++
> migration.c | 28 ++++++++++++++++++++++++++++
> migration.h | 4 ++++
> qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
> qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
> 6 files changed, 147 insertions(+), 1 deletions(-)
>
> diff --git a/arch_init.c b/arch_init.c
> index 7f12317..9833d54 100644
> --- a/arch_init.c
> +++ b/arch_init.c
> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
> typedef struct AccountingInfo {
> uint64_t dup_pages;
> uint64_t norm_pages;
> + uint64_t xbzrle_bytes;
> + uint64_t xbzrle_pages;
> + uint64_t xbzrle_cache_miss;
> uint64_t iterations;
> + uint64_t xbzrle_overflows;
> } AccountingInfo;
>
> static AccountingInfo acct_info;
> @@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
> return acct_info.norm_pages;
> }
>
> +uint64_t xbzrle_mig_bytes_transferred(void)
> +{
> + return acct_info.xbzrle_bytes;
> +}
> +
> +uint64_t xbzrle_mig_pages_transferred(void)
> +{
> + return acct_info.xbzrle_pages;
> +}
> +
> +uint64_t xbzrle_mig_pages_cache_miss(void)
> +{
> + return acct_info.xbzrle_cache_miss;
> +}
> +
> +uint64_t xbzrle_mig_pages_overflow(void)
> +{
> + return acct_info.xbzrle_overflows;
> +}
> +
> static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
> int cont, int flag)
> {
> @@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> if (!cache_is_cached(XBZRLE.cache, current_addr)) {
> cache_insert(XBZRLE.cache, current_addr,
> g_memdup(current_data, TARGET_PAGE_SIZE));
> + acct_info.xbzrle_cache_miss++;
> return -1;
> }
>
> @@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> return 0;
> } else if (encoded_len == -1) {
> DPRINTF("Overflow\n");
> + acct_info.xbzrle_overflows++;
> /* update data in the cache */
> memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
> return -1;
> @@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> qemu_put_be16(f, encoded_len);
> qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
> bytes_sent = encoded_len + 1 + 2;
> + acct_info.xbzrle_pages++;
> + acct_info.xbzrle_bytes += bytes_sent;
>
> return bytes_sent;
> }
> diff --git a/hmp.c b/hmp.c
> index 9770d7b..383d5b1 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
> info->disk->total >> 10);
> }
>
> + if (info->has_xbzrle_cache) {
> + monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
> + info->xbzrle_cache->cache_size);
> + if (info->xbzrle_cache->has_xbzrle_bytes) {
> + monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
> + info->xbzrle_cache->xbzrle_bytes >> 10);
> + }
> + if (info->xbzrle_cache->has_xbzrle_pages) {
> + monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
> + info->xbzrle_cache->xbzrle_pages);
> + }
> + if (info->xbzrle_cache->has_xbzrle_cache_miss) {
> + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
> + info->xbzrle_cache->xbzrle_cache_miss);
> + }
> + if (info->xbzrle_cache->has_xbzrle_overflow) {
> + monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
> + info->xbzrle_cache->xbzrle_overflow);
> + }
> + }
> +
> qapi_free_MigrationInfo(info);
> qapi_free_MigrationParameters(params);
> }
> diff --git a/migration.c b/migration.c
> index 4dc99ba..fb802bc 100644
> --- a/migration.c
> +++ b/migration.c
> @@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> return params;
> }
>
> +static void get_xbzrle_cache_stats(MigrationInfo *info)
> +{
> + if (migrate_use_xbzrle()) {
> + info->has_xbzrle_cache = true;
> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> + info->xbzrle_cache->has_xbzrle_bytes = true;
> + info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
> + info->xbzrle_cache->has_xbzrle_pages = true;
> + info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
> + info->xbzrle_cache->has_xbzrle_cache_miss = true;
> + info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
> + info->xbzrle_cache->has_xbzrle_overflow = true;
> + info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
> + }
> +}
> +
> MigrationInfo *qmp_query_migrate(Error **errp)
> {
> MigrationInfo *info = g_malloc0(sizeof(*info));
> @@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> switch (s->state) {
> case MIG_STATE_SETUP:
> /* no migration has happened ever */
> +
> + /* display xbzrle cache size */
> + if (migrate_use_xbzrle()) {
> + info->has_xbzrle_cache = true;
> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> + }
Is it really useful to return this in MIG_SETUP? Can't the cache size
be queried by some query- command?
> break;
> case MIG_STATE_ACTIVE:
> info->has_status = true;
> @@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> info->disk->remaining = blk_mig_bytes_remaining();
> info->disk->total = blk_mig_bytes_total();
> }
> +
> + get_xbzrle_cache_stats(info);
> break;
> case MIG_STATE_COMPLETED:
> + get_xbzrle_cache_stats(info);
> +
> info->has_status = true;
> info->status = g_strdup("completed");
>
> diff --git a/migration.h b/migration.h
> index e4a7cd7..a9852fc 100644
> --- a/migration.h
> +++ b/migration.h
> @@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
> uint64_t dup_mig_pages_transferred(void);
> uint64_t norm_mig_bytes_transferred(void);
> uint64_t norm_mig_pages_transferred(void);
> +uint64_t xbzrle_mig_bytes_transferred(void);
> +uint64_t xbzrle_mig_pages_transferred(void);
> +uint64_t xbzrle_mig_pages_overflow(void);
> +uint64_t xbzrle_mig_pages_cache_miss(void);
>
> /**
> * @migrate_add_blocker - prevent migration from proceeding
> diff --git a/qapi-schema.json b/qapi-schema.json
> index a936714..91dee72 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -275,6 +275,31 @@
> 'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
>
> ##
> +# @XBZRLECacheStats
> +#
> +# Detailed XBZRLE migration cache statistics
> +#
> +# @cache-size: XBZRLE cache size
> +#
> +# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
> +# only returned when migration is active or completed
s/xbzrle-bytes/transferred-bytes
> +#
> +# @xbzrle-pages: @optional, amount of pages transferred to the target VM
> +# only returned when migration is active or completed
s/xbzrle-pages/transferred-pages
> +#
> +# @xbzrle-cache-miss: @optional, number of cache miss
> +# only returned when migration is active or completed
s/xbzrle/xbzrle//
> +#
> +# @xbzrle-overflow: @optional, number of overflows
> +# only returned when migration is active or completed
s/xbzrle///
Besides, all these parameters shouldn't be optional as they are unconditionally
included (BZRLECacheStats itself is optional as returned by query-migrate).
> +#
> +# Since: 1.2
> +##
> +{ 'type': 'XBZRLECacheStats',
> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
> +
> +##
> # @MigrationInfo
> #
> # Information about current migration process.
> @@ -292,11 +317,16 @@
> # status, only returned if status is 'active' and it is a block
> # migration
> #
> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
> +# migration statistics, only returned if XBZRLE feature is on
> +# (since 1.2)
> +#
> # Since: 0.14.0
> ##
> { 'type': 'MigrationInfo',
> 'data': {'*status': 'str', '*ram': 'MigrationStats',
> - '*disk': 'MigrationStats'} }
> + '*disk': 'MigrationStats',
> + '*xbzrle-cache': 'XBZRLECacheStats'} }
>
> ##
> # @query-migrate
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index a5a67eb..0546f42 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -2106,6 +2106,17 @@ The main json-object contains the following:
> - "transferred": amount transferred (json-int)
> - "remaining": amount remaining (json-int)
> - "total": total (json-int)
> +- "xbzrle-cache": only present if XBZRLE is active.
> + It is a json-object with the following XBZRLE information:
> + - "cache-size": XBZRLE cache size
> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
> + status is "active" or "completed"
> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
> + status is "active" or "completed"
> + - "cache-miss": number of cache misses, only present if
> + status is "active" or "completed"
> + - "overflow": number of XBZRLE overflows, only present if
> + status is "active" or "completed"
> Examples:
>
> 1. Before the first migration
> @@ -2170,6 +2181,30 @@ Examples:
> }
> }
>
> +6. Migration is being performed and XBZRLE is active:
> +
> +-> { "execute": "query-migrate" }
> +<- {
> + "return":{
> + "status":"active",
> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
> + "ram":{
> + "total":1057024,
> + "remaining":1053304,
> + "transferred":3720,
> + "duplicate": 10,
> + "normal" : 3333
> + },
> + "cache":{
> + "cache-size": 1024
> + "xbzrle-transferred":20971520,
> + "xbzrle-pages":2444343,
> + "xbzrle-cache-miss":2244,
> + "xbzrle-overflow":34434
> + }
> + }
> + }
> +
> EQMP
>
> {
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-30 19:37 ` Luiz Capitulino
@ 2012-07-31 8:31 ` Orit Wasserman
2012-07-31 13:16 ` Luiz Capitulino
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-07-31 8:31 UTC (permalink / raw)
To: Luiz Capitulino
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel,
Benoit Hudzia, mdroth, blauwirbel, Petter Svard, chegu_vinod, avi,
Aidan Shribman, pbonzini, eblake
On 07/30/2012 10:37 PM, Luiz Capitulino wrote:
> On Sun, 29 Jul 2012 12:43:02 +0300
> Orit Wasserman <owasserm@redhat.com> wrote:
>
>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
>> Signed-off-by: Petter Svard <petters@cs.umu.se>
>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>> arch_init.c | 28 ++++++++++++++++++++++++++++
>> hmp.c | 21 +++++++++++++++++++++
>> migration.c | 28 ++++++++++++++++++++++++++++
>> migration.h | 4 ++++
>> qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
>> qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
>> 6 files changed, 147 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch_init.c b/arch_init.c
>> index 7f12317..9833d54 100644
>> --- a/arch_init.c
>> +++ b/arch_init.c
>> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
>> typedef struct AccountingInfo {
>> uint64_t dup_pages;
>> uint64_t norm_pages;
>> + uint64_t xbzrle_bytes;
>> + uint64_t xbzrle_pages;
>> + uint64_t xbzrle_cache_miss;
>> uint64_t iterations;
>> + uint64_t xbzrle_overflows;
>> } AccountingInfo;
>>
>> static AccountingInfo acct_info;
>> @@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
>> return acct_info.norm_pages;
>> }
>>
>> +uint64_t xbzrle_mig_bytes_transferred(void)
>> +{
>> + return acct_info.xbzrle_bytes;
>> +}
>> +
>> +uint64_t xbzrle_mig_pages_transferred(void)
>> +{
>> + return acct_info.xbzrle_pages;
>> +}
>> +
>> +uint64_t xbzrle_mig_pages_cache_miss(void)
>> +{
>> + return acct_info.xbzrle_cache_miss;
>> +}
>> +
>> +uint64_t xbzrle_mig_pages_overflow(void)
>> +{
>> + return acct_info.xbzrle_overflows;
>> +}
>> +
>> static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
>> int cont, int flag)
>> {
>> @@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>> if (!cache_is_cached(XBZRLE.cache, current_addr)) {
>> cache_insert(XBZRLE.cache, current_addr,
>> g_memdup(current_data, TARGET_PAGE_SIZE));
>> + acct_info.xbzrle_cache_miss++;
>> return -1;
>> }
>>
>> @@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>> return 0;
>> } else if (encoded_len == -1) {
>> DPRINTF("Overflow\n");
>> + acct_info.xbzrle_overflows++;
>> /* update data in the cache */
>> memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
>> return -1;
>> @@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>> qemu_put_be16(f, encoded_len);
>> qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
>> bytes_sent = encoded_len + 1 + 2;
>> + acct_info.xbzrle_pages++;
>> + acct_info.xbzrle_bytes += bytes_sent;
>>
>> return bytes_sent;
>> }
>> diff --git a/hmp.c b/hmp.c
>> index 9770d7b..383d5b1 100644
>> --- a/hmp.c
>> +++ b/hmp.c
>> @@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
>> info->disk->total >> 10);
>> }
>>
>> + if (info->has_xbzrle_cache) {
>> + monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
>> + info->xbzrle_cache->cache_size);
>> + if (info->xbzrle_cache->has_xbzrle_bytes) {
>> + monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
>> + info->xbzrle_cache->xbzrle_bytes >> 10);
>> + }
>> + if (info->xbzrle_cache->has_xbzrle_pages) {
>> + monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
>> + info->xbzrle_cache->xbzrle_pages);
>> + }
>> + if (info->xbzrle_cache->has_xbzrle_cache_miss) {
>> + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
>> + info->xbzrle_cache->xbzrle_cache_miss);
>> + }
>> + if (info->xbzrle_cache->has_xbzrle_overflow) {
>> + monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
>> + info->xbzrle_cache->xbzrle_overflow);
>> + }
>> + }
>> +
>> qapi_free_MigrationInfo(info);
>> qapi_free_MigrationParameters(params);
>> }
>> diff --git a/migration.c b/migration.c
>> index 4dc99ba..fb802bc 100644
>> --- a/migration.c
>> +++ b/migration.c
>> @@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>> return params;
>> }
>>
>> +static void get_xbzrle_cache_stats(MigrationInfo *info)
>> +{
>> + if (migrate_use_xbzrle()) {
>> + info->has_xbzrle_cache = true;
>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
>> + info->xbzrle_cache->has_xbzrle_bytes = true;
>> + info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
>> + info->xbzrle_cache->has_xbzrle_pages = true;
>> + info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
>> + info->xbzrle_cache->has_xbzrle_cache_miss = true;
>> + info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
>> + info->xbzrle_cache->has_xbzrle_overflow = true;
>> + info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
>> + }
>> +}
>> +
>> MigrationInfo *qmp_query_migrate(Error **errp)
>> {
>> MigrationInfo *info = g_malloc0(sizeof(*info));
>> @@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
>> switch (s->state) {
>> case MIG_STATE_SETUP:
>> /* no migration has happened ever */
>> +
>> + /* display xbzrle cache size */
>> + if (migrate_use_xbzrle()) {
>> + info->has_xbzrle_cache = true;
>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
>> + }
>
> Is it really useful to return this in MIG_SETUP? Can't the cache size
> be queried by some query- command?
I like it this way and it is very simple to use, you need to use query-migrate command if you do migration
anyway.
Otherwise we will need to add a query command for each configurable parameters,
so one for speed and another for downtime and probably more in the future.
This way we use one command to query the migration setup.
Orit
>
>> break;
>> case MIG_STATE_ACTIVE:
>> info->has_status = true;
>> @@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
>> info->disk->remaining = blk_mig_bytes_remaining();
>> info->disk->total = blk_mig_bytes_total();
>> }
>> +
>> + get_xbzrle_cache_stats(info);
>> break;
>> case MIG_STATE_COMPLETED:
>> + get_xbzrle_cache_stats(info);
>> +
>> info->has_status = true;
>> info->status = g_strdup("completed");
>>
>> diff --git a/migration.h b/migration.h
>> index e4a7cd7..a9852fc 100644
>> --- a/migration.h
>> +++ b/migration.h
>> @@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
>> uint64_t dup_mig_pages_transferred(void);
>> uint64_t norm_mig_bytes_transferred(void);
>> uint64_t norm_mig_pages_transferred(void);
>> +uint64_t xbzrle_mig_bytes_transferred(void);
>> +uint64_t xbzrle_mig_pages_transferred(void);
>> +uint64_t xbzrle_mig_pages_overflow(void);
>> +uint64_t xbzrle_mig_pages_cache_miss(void);
>>
>> /**
>> * @migrate_add_blocker - prevent migration from proceeding
>> diff --git a/qapi-schema.json b/qapi-schema.json
>> index a936714..91dee72 100644
>> --- a/qapi-schema.json
>> +++ b/qapi-schema.json
>> @@ -275,6 +275,31 @@
>> 'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
>>
>> ##
>> +# @XBZRLECacheStats
>> +#
>> +# Detailed XBZRLE migration cache statistics
>> +#
>> +# @cache-size: XBZRLE cache size
>> +#
>> +# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
>> +# only returned when migration is active or completed
>
> s/xbzrle-bytes/transferred-bytes
>
>> +#
>> +# @xbzrle-pages: @optional, amount of pages transferred to the target VM
>> +# only returned when migration is active or completed
>
> s/xbzrle-pages/transferred-pages
>
>> +#
>> +# @xbzrle-cache-miss: @optional, number of cache miss
>> +# only returned when migration is active or completed
>
> s/xbzrle/xbzrle//
>
>> +#
>> +# @xbzrle-overflow: @optional, number of overflows
>> +# only returned when migration is active or completed
>
> s/xbzrle///
>
> Besides, all these parameters shouldn't be optional as they are unconditionally
> included (BZRLECacheStats itself is optional as returned by query-migrate).
>
>> +#
>> +# Since: 1.2
>> +##
>> +{ 'type': 'XBZRLECacheStats',
>> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
>> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
>> +
>> +##
>> # @MigrationInfo
>> #
>> # Information about current migration process.
>> @@ -292,11 +317,16 @@
>> # status, only returned if status is 'active' and it is a block
>> # migration
>> #
>> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
>> +# migration statistics, only returned if XBZRLE feature is on
>> +# (since 1.2)
>> +#
>> # Since: 0.14.0
>> ##
>> { 'type': 'MigrationInfo',
>> 'data': {'*status': 'str', '*ram': 'MigrationStats',
>> - '*disk': 'MigrationStats'} }
>> + '*disk': 'MigrationStats',
>> + '*xbzrle-cache': 'XBZRLECacheStats'} }
>>
>> ##
>> # @query-migrate
>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>> index a5a67eb..0546f42 100644
>> --- a/qmp-commands.hx
>> +++ b/qmp-commands.hx
>> @@ -2106,6 +2106,17 @@ The main json-object contains the following:
>> - "transferred": amount transferred (json-int)
>> - "remaining": amount remaining (json-int)
>> - "total": total (json-int)
>> +- "xbzrle-cache": only present if XBZRLE is active.
>> + It is a json-object with the following XBZRLE information:
>> + - "cache-size": XBZRLE cache size
>> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
>> + status is "active" or "completed"
>> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
>> + status is "active" or "completed"
>> + - "cache-miss": number of cache misses, only present if
>> + status is "active" or "completed"
>> + - "overflow": number of XBZRLE overflows, only present if
>> + status is "active" or "completed"
>> Examples:
>>
>> 1. Before the first migration
>> @@ -2170,6 +2181,30 @@ Examples:
>> }
>> }
>>
>> +6. Migration is being performed and XBZRLE is active:
>> +
>> +-> { "execute": "query-migrate" }
>> +<- {
>> + "return":{
>> + "status":"active",
>> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
>> + "ram":{
>> + "total":1057024,
>> + "remaining":1053304,
>> + "transferred":3720,
>> + "duplicate": 10,
>> + "normal" : 3333
>> + },
>> + "cache":{
>> + "cache-size": 1024
>> + "xbzrle-transferred":20971520,
>> + "xbzrle-pages":2444343,
>> + "xbzrle-cache-miss":2244,
>> + "xbzrle-overflow":34434
>> + }
>> + }
>> + }
>> +
>> EQMP
>>
>> {
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-31 8:31 ` Orit Wasserman
@ 2012-07-31 13:16 ` Luiz Capitulino
2012-07-31 14:13 ` Orit Wasserman
0 siblings, 1 reply; 31+ messages in thread
From: Luiz Capitulino @ 2012-07-31 13:16 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel,
Benoit Hudzia, mdroth, blauwirbel, Petter Svard, chegu_vinod, avi,
Aidan Shribman, pbonzini, eblake
On Tue, 31 Jul 2012 11:31:09 +0300
Orit Wasserman <owasserm@redhat.com> wrote:
> On 07/30/2012 10:37 PM, Luiz Capitulino wrote:
> > On Sun, 29 Jul 2012 12:43:02 +0300
> > Orit Wasserman <owasserm@redhat.com> wrote:
> >
> >> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> >> Signed-off-by: Petter Svard <petters@cs.umu.se>
> >> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> >> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> >> Signed-off-by: Juan Quintela <quintela@redhat.com>
> >> ---
> >> arch_init.c | 28 ++++++++++++++++++++++++++++
> >> hmp.c | 21 +++++++++++++++++++++
> >> migration.c | 28 ++++++++++++++++++++++++++++
> >> migration.h | 4 ++++
> >> qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
> >> qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
> >> 6 files changed, 147 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/arch_init.c b/arch_init.c
> >> index 7f12317..9833d54 100644
> >> --- a/arch_init.c
> >> +++ b/arch_init.c
> >> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
> >> typedef struct AccountingInfo {
> >> uint64_t dup_pages;
> >> uint64_t norm_pages;
> >> + uint64_t xbzrle_bytes;
> >> + uint64_t xbzrle_pages;
> >> + uint64_t xbzrle_cache_miss;
> >> uint64_t iterations;
> >> + uint64_t xbzrle_overflows;
> >> } AccountingInfo;
> >>
> >> static AccountingInfo acct_info;
> >> @@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
> >> return acct_info.norm_pages;
> >> }
> >>
> >> +uint64_t xbzrle_mig_bytes_transferred(void)
> >> +{
> >> + return acct_info.xbzrle_bytes;
> >> +}
> >> +
> >> +uint64_t xbzrle_mig_pages_transferred(void)
> >> +{
> >> + return acct_info.xbzrle_pages;
> >> +}
> >> +
> >> +uint64_t xbzrle_mig_pages_cache_miss(void)
> >> +{
> >> + return acct_info.xbzrle_cache_miss;
> >> +}
> >> +
> >> +uint64_t xbzrle_mig_pages_overflow(void)
> >> +{
> >> + return acct_info.xbzrle_overflows;
> >> +}
> >> +
> >> static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
> >> int cont, int flag)
> >> {
> >> @@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >> if (!cache_is_cached(XBZRLE.cache, current_addr)) {
> >> cache_insert(XBZRLE.cache, current_addr,
> >> g_memdup(current_data, TARGET_PAGE_SIZE));
> >> + acct_info.xbzrle_cache_miss++;
> >> return -1;
> >> }
> >>
> >> @@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >> return 0;
> >> } else if (encoded_len == -1) {
> >> DPRINTF("Overflow\n");
> >> + acct_info.xbzrle_overflows++;
> >> /* update data in the cache */
> >> memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
> >> return -1;
> >> @@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >> qemu_put_be16(f, encoded_len);
> >> qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
> >> bytes_sent = encoded_len + 1 + 2;
> >> + acct_info.xbzrle_pages++;
> >> + acct_info.xbzrle_bytes += bytes_sent;
> >>
> >> return bytes_sent;
> >> }
> >> diff --git a/hmp.c b/hmp.c
> >> index 9770d7b..383d5b1 100644
> >> --- a/hmp.c
> >> +++ b/hmp.c
> >> @@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
> >> info->disk->total >> 10);
> >> }
> >>
> >> + if (info->has_xbzrle_cache) {
> >> + monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
> >> + info->xbzrle_cache->cache_size);
> >> + if (info->xbzrle_cache->has_xbzrle_bytes) {
> >> + monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
> >> + info->xbzrle_cache->xbzrle_bytes >> 10);
> >> + }
> >> + if (info->xbzrle_cache->has_xbzrle_pages) {
> >> + monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
> >> + info->xbzrle_cache->xbzrle_pages);
> >> + }
> >> + if (info->xbzrle_cache->has_xbzrle_cache_miss) {
> >> + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
> >> + info->xbzrle_cache->xbzrle_cache_miss);
> >> + }
> >> + if (info->xbzrle_cache->has_xbzrle_overflow) {
> >> + monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
> >> + info->xbzrle_cache->xbzrle_overflow);
> >> + }
> >> + }
> >> +
> >> qapi_free_MigrationInfo(info);
> >> qapi_free_MigrationParameters(params);
> >> }
> >> diff --git a/migration.c b/migration.c
> >> index 4dc99ba..fb802bc 100644
> >> --- a/migration.c
> >> +++ b/migration.c
> >> @@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> >> return params;
> >> }
> >>
> >> +static void get_xbzrle_cache_stats(MigrationInfo *info)
> >> +{
> >> + if (migrate_use_xbzrle()) {
> >> + info->has_xbzrle_cache = true;
> >> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> >> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> >> + info->xbzrle_cache->has_xbzrle_bytes = true;
> >> + info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
> >> + info->xbzrle_cache->has_xbzrle_pages = true;
> >> + info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
> >> + info->xbzrle_cache->has_xbzrle_cache_miss = true;
> >> + info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
> >> + info->xbzrle_cache->has_xbzrle_overflow = true;
> >> + info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
> >> + }
> >> +}
> >> +
> >> MigrationInfo *qmp_query_migrate(Error **errp)
> >> {
> >> MigrationInfo *info = g_malloc0(sizeof(*info));
> >> @@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> >> switch (s->state) {
> >> case MIG_STATE_SETUP:
> >> /* no migration has happened ever */
> >> +
> >> + /* display xbzrle cache size */
> >> + if (migrate_use_xbzrle()) {
> >> + info->has_xbzrle_cache = true;
> >> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> >> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> >> + }
> >
> > Is it really useful to return this in MIG_SETUP? Can't the cache size
> > be queried by some query- command?
> I like it this way and it is very simple to use, you need to use query-migrate command if you do migration
> anyway.
But this will only be returned before a migration takes place. Then it will
never be returned again. Doesn't seem to be the right place for it.
> Otherwise we will need to add a query command for each configurable parameters,
> so one for speed and another for downtime and probably more in the future.
I don't think this is a problem. We're trying to design QMP commands as we
would design a C API, and I'd have different functions to query different things.
Besides, let's not mix what's best to a human user and what's best for a
machine protocol. If we add different query commands for different parameters,
then it's possible to call them from 'info migrate' if you wish.
> This way we use one command to query the migration setup.
Again, that information would only be returned before a first migration
occurs.
>
> Orit
> >
> >> break;
> >> case MIG_STATE_ACTIVE:
> >> info->has_status = true;
> >> @@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> >> info->disk->remaining = blk_mig_bytes_remaining();
> >> info->disk->total = blk_mig_bytes_total();
> >> }
> >> +
> >> + get_xbzrle_cache_stats(info);
> >> break;
> >> case MIG_STATE_COMPLETED:
> >> + get_xbzrle_cache_stats(info);
> >> +
> >> info->has_status = true;
> >> info->status = g_strdup("completed");
> >>
> >> diff --git a/migration.h b/migration.h
> >> index e4a7cd7..a9852fc 100644
> >> --- a/migration.h
> >> +++ b/migration.h
> >> @@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
> >> uint64_t dup_mig_pages_transferred(void);
> >> uint64_t norm_mig_bytes_transferred(void);
> >> uint64_t norm_mig_pages_transferred(void);
> >> +uint64_t xbzrle_mig_bytes_transferred(void);
> >> +uint64_t xbzrle_mig_pages_transferred(void);
> >> +uint64_t xbzrle_mig_pages_overflow(void);
> >> +uint64_t xbzrle_mig_pages_cache_miss(void);
> >>
> >> /**
> >> * @migrate_add_blocker - prevent migration from proceeding
> >> diff --git a/qapi-schema.json b/qapi-schema.json
> >> index a936714..91dee72 100644
> >> --- a/qapi-schema.json
> >> +++ b/qapi-schema.json
> >> @@ -275,6 +275,31 @@
> >> 'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
> >>
> >> ##
> >> +# @XBZRLECacheStats
> >> +#
> >> +# Detailed XBZRLE migration cache statistics
> >> +#
> >> +# @cache-size: XBZRLE cache size
> >> +#
> >> +# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
> >> +# only returned when migration is active or completed
> >
> > s/xbzrle-bytes/transferred-bytes
> >
> >> +#
> >> +# @xbzrle-pages: @optional, amount of pages transferred to the target VM
> >> +# only returned when migration is active or completed
> >
> > s/xbzrle-pages/transferred-pages
> >
> >> +#
> >> +# @xbzrle-cache-miss: @optional, number of cache miss
> >> +# only returned when migration is active or completed
> >
> > s/xbzrle/xbzrle//
> >
> >> +#
> >> +# @xbzrle-overflow: @optional, number of overflows
> >> +# only returned when migration is active or completed
> >
> > s/xbzrle///
> >
> > Besides, all these parameters shouldn't be optional as they are unconditionally
> > included (BZRLECacheStats itself is optional as returned by query-migrate).
> >
> >> +#
> >> +# Since: 1.2
> >> +##
> >> +{ 'type': 'XBZRLECacheStats',
> >> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
> >> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
> >> +
> >> +##
> >> # @MigrationInfo
> >> #
> >> # Information about current migration process.
> >> @@ -292,11 +317,16 @@
> >> # status, only returned if status is 'active' and it is a block
> >> # migration
> >> #
> >> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
> >> +# migration statistics, only returned if XBZRLE feature is on
> >> +# (since 1.2)
> >> +#
> >> # Since: 0.14.0
> >> ##
> >> { 'type': 'MigrationInfo',
> >> 'data': {'*status': 'str', '*ram': 'MigrationStats',
> >> - '*disk': 'MigrationStats'} }
> >> + '*disk': 'MigrationStats',
> >> + '*xbzrle-cache': 'XBZRLECacheStats'} }
> >>
> >> ##
> >> # @query-migrate
> >> diff --git a/qmp-commands.hx b/qmp-commands.hx
> >> index a5a67eb..0546f42 100644
> >> --- a/qmp-commands.hx
> >> +++ b/qmp-commands.hx
> >> @@ -2106,6 +2106,17 @@ The main json-object contains the following:
> >> - "transferred": amount transferred (json-int)
> >> - "remaining": amount remaining (json-int)
> >> - "total": total (json-int)
> >> +- "xbzrle-cache": only present if XBZRLE is active.
> >> + It is a json-object with the following XBZRLE information:
> >> + - "cache-size": XBZRLE cache size
> >> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
> >> + status is "active" or "completed"
> >> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
> >> + status is "active" or "completed"
> >> + - "cache-miss": number of cache misses, only present if
> >> + status is "active" or "completed"
> >> + - "overflow": number of XBZRLE overflows, only present if
> >> + status is "active" or "completed"
> >> Examples:
> >>
> >> 1. Before the first migration
> >> @@ -2170,6 +2181,30 @@ Examples:
> >> }
> >> }
> >>
> >> +6. Migration is being performed and XBZRLE is active:
> >> +
> >> +-> { "execute": "query-migrate" }
> >> +<- {
> >> + "return":{
> >> + "status":"active",
> >> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
> >> + "ram":{
> >> + "total":1057024,
> >> + "remaining":1053304,
> >> + "transferred":3720,
> >> + "duplicate": 10,
> >> + "normal" : 3333
> >> + },
> >> + "cache":{
> >> + "cache-size": 1024
> >> + "xbzrle-transferred":20971520,
> >> + "xbzrle-pages":2444343,
> >> + "xbzrle-cache-miss":2244,
> >> + "xbzrle-overflow":34434
> >> + }
> >> + }
> >> + }
> >> +
> >> EQMP
> >>
> >> {
> >
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-31 13:16 ` Luiz Capitulino
@ 2012-07-31 14:13 ` Orit Wasserman
2012-07-31 15:54 ` Luiz Capitulino
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-07-31 14:13 UTC (permalink / raw)
To: Luiz Capitulino
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel,
Benoit Hudzia, mdroth, blauwirbel, Petter Svard, chegu_vinod, avi,
Aidan Shribman, pbonzini, eblake
On 07/31/2012 04:16 PM, Luiz Capitulino wrote:
> On Tue, 31 Jul 2012 11:31:09 +0300
> Orit Wasserman <owasserm@redhat.com> wrote:
>
>> On 07/30/2012 10:37 PM, Luiz Capitulino wrote:
>>> On Sun, 29 Jul 2012 12:43:02 +0300
>>> Orit Wasserman <owasserm@redhat.com> wrote:
>>>
>>>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
>>>> Signed-off-by: Petter Svard <petters@cs.umu.se>
>>>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
>>>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
>>>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>>>> ---
>>>> arch_init.c | 28 ++++++++++++++++++++++++++++
>>>> hmp.c | 21 +++++++++++++++++++++
>>>> migration.c | 28 ++++++++++++++++++++++++++++
>>>> migration.h | 4 ++++
>>>> qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
>>>> qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
>>>> 6 files changed, 147 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/arch_init.c b/arch_init.c
>>>> index 7f12317..9833d54 100644
>>>> --- a/arch_init.c
>>>> +++ b/arch_init.c
>>>> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
>>>> typedef struct AccountingInfo {
>>>> uint64_t dup_pages;
>>>> uint64_t norm_pages;
>>>> + uint64_t xbzrle_bytes;
>>>> + uint64_t xbzrle_pages;
>>>> + uint64_t xbzrle_cache_miss;
>>>> uint64_t iterations;
>>>> + uint64_t xbzrle_overflows;
>>>> } AccountingInfo;
>>>>
>>>> static AccountingInfo acct_info;
>>>> @@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
>>>> return acct_info.norm_pages;
>>>> }
>>>>
>>>> +uint64_t xbzrle_mig_bytes_transferred(void)
>>>> +{
>>>> + return acct_info.xbzrle_bytes;
>>>> +}
>>>> +
>>>> +uint64_t xbzrle_mig_pages_transferred(void)
>>>> +{
>>>> + return acct_info.xbzrle_pages;
>>>> +}
>>>> +
>>>> +uint64_t xbzrle_mig_pages_cache_miss(void)
>>>> +{
>>>> + return acct_info.xbzrle_cache_miss;
>>>> +}
>>>> +
>>>> +uint64_t xbzrle_mig_pages_overflow(void)
>>>> +{
>>>> + return acct_info.xbzrle_overflows;
>>>> +}
>>>> +
>>>> static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
>>>> int cont, int flag)
>>>> {
>>>> @@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>>>> if (!cache_is_cached(XBZRLE.cache, current_addr)) {
>>>> cache_insert(XBZRLE.cache, current_addr,
>>>> g_memdup(current_data, TARGET_PAGE_SIZE));
>>>> + acct_info.xbzrle_cache_miss++;
>>>> return -1;
>>>> }
>>>>
>>>> @@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>>>> return 0;
>>>> } else if (encoded_len == -1) {
>>>> DPRINTF("Overflow\n");
>>>> + acct_info.xbzrle_overflows++;
>>>> /* update data in the cache */
>>>> memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
>>>> return -1;
>>>> @@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
>>>> qemu_put_be16(f, encoded_len);
>>>> qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
>>>> bytes_sent = encoded_len + 1 + 2;
>>>> + acct_info.xbzrle_pages++;
>>>> + acct_info.xbzrle_bytes += bytes_sent;
>>>>
>>>> return bytes_sent;
>>>> }
>>>> diff --git a/hmp.c b/hmp.c
>>>> index 9770d7b..383d5b1 100644
>>>> --- a/hmp.c
>>>> +++ b/hmp.c
>>>> @@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
>>>> info->disk->total >> 10);
>>>> }
>>>>
>>>> + if (info->has_xbzrle_cache) {
>>>> + monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
>>>> + info->xbzrle_cache->cache_size);
>>>> + if (info->xbzrle_cache->has_xbzrle_bytes) {
>>>> + monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
>>>> + info->xbzrle_cache->xbzrle_bytes >> 10);
>>>> + }
>>>> + if (info->xbzrle_cache->has_xbzrle_pages) {
>>>> + monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
>>>> + info->xbzrle_cache->xbzrle_pages);
>>>> + }
>>>> + if (info->xbzrle_cache->has_xbzrle_cache_miss) {
>>>> + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
>>>> + info->xbzrle_cache->xbzrle_cache_miss);
>>>> + }
>>>> + if (info->xbzrle_cache->has_xbzrle_overflow) {
>>>> + monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
>>>> + info->xbzrle_cache->xbzrle_overflow);
>>>> + }
>>>> + }
>>>> +
>>>> qapi_free_MigrationInfo(info);
>>>> qapi_free_MigrationParameters(params);
>>>> }
>>>> diff --git a/migration.c b/migration.c
>>>> index 4dc99ba..fb802bc 100644
>>>> --- a/migration.c
>>>> +++ b/migration.c
>>>> @@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>>>> return params;
>>>> }
>>>>
>>>> +static void get_xbzrle_cache_stats(MigrationInfo *info)
>>>> +{
>>>> + if (migrate_use_xbzrle()) {
>>>> + info->has_xbzrle_cache = true;
>>>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
>>>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
>>>> + info->xbzrle_cache->has_xbzrle_bytes = true;
>>>> + info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
>>>> + info->xbzrle_cache->has_xbzrle_pages = true;
>>>> + info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
>>>> + info->xbzrle_cache->has_xbzrle_cache_miss = true;
>>>> + info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
>>>> + info->xbzrle_cache->has_xbzrle_overflow = true;
>>>> + info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
>>>> + }
>>>> +}
>>>> +
>>>> MigrationInfo *qmp_query_migrate(Error **errp)
>>>> {
>>>> MigrationInfo *info = g_malloc0(sizeof(*info));
>>>> @@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
>>>> switch (s->state) {
>>>> case MIG_STATE_SETUP:
>>>> /* no migration has happened ever */
>>>> +
>>>> + /* display xbzrle cache size */
>>>> + if (migrate_use_xbzrle()) {
>>>> + info->has_xbzrle_cache = true;
>>>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
>>>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
>>>> + }
>>>
>>> Is it really useful to return this in MIG_SETUP? Can't the cache size
>>> be queried by some query- command?
>> I like it this way and it is very simple to use, you need to use query-migrate command if you do migration
>> anyway.
>
> But this will only be returned before a migration takes place. Then it will
> never be returned again. Doesn't seem to be the right place for it.
It is returned also in MIG_ACTIVE and MIG_COMPLETE (when XBZRLE are active).
>
>> Otherwise we will need to add a query command for each configurable parameters,
>> so one for speed and another for downtime and probably more in the future.
>
> I don't think this is a problem. We're trying to design QMP commands as we
> would design a C API, and I'd have different functions to query different things.
>
> Besides, let's not mix what's best to a human user and what's best for a
> machine protocol. If we add different query commands for different parameters,
> then it's possible to call them from 'info migrate' if you wish.
sounds reasonable, I will change it.
Orit
>
>> This way we use one command to query the migration setup.
>
> Again, that information would only be returned before a first migration
> occurs.
>
>>
>> Orit
>>>
>>>> break;
>>>> case MIG_STATE_ACTIVE:
>>>> info->has_status = true;
>>>> @@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
>>>> info->disk->remaining = blk_mig_bytes_remaining();
>>>> info->disk->total = blk_mig_bytes_total();
>>>> }
>>>> +
>>>> + get_xbzrle_cache_stats(info);
>>>> break;
>>>> case MIG_STATE_COMPLETED:
>>>> + get_xbzrle_cache_stats(info);
>>>> +
>>>> info->has_status = true;
>>>> info->status = g_strdup("completed");
>>>>
>>>> diff --git a/migration.h b/migration.h
>>>> index e4a7cd7..a9852fc 100644
>>>> --- a/migration.h
>>>> +++ b/migration.h
>>>> @@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
>>>> uint64_t dup_mig_pages_transferred(void);
>>>> uint64_t norm_mig_bytes_transferred(void);
>>>> uint64_t norm_mig_pages_transferred(void);
>>>> +uint64_t xbzrle_mig_bytes_transferred(void);
>>>> +uint64_t xbzrle_mig_pages_transferred(void);
>>>> +uint64_t xbzrle_mig_pages_overflow(void);
>>>> +uint64_t xbzrle_mig_pages_cache_miss(void);
>>>>
>>>> /**
>>>> * @migrate_add_blocker - prevent migration from proceeding
>>>> diff --git a/qapi-schema.json b/qapi-schema.json
>>>> index a936714..91dee72 100644
>>>> --- a/qapi-schema.json
>>>> +++ b/qapi-schema.json
>>>> @@ -275,6 +275,31 @@
>>>> 'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
>>>>
>>>> ##
>>>> +# @XBZRLECacheStats
>>>> +#
>>>> +# Detailed XBZRLE migration cache statistics
>>>> +#
>>>> +# @cache-size: XBZRLE cache size
>>>> +#
>>>> +# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
>>>> +# only returned when migration is active or completed
>>>
>>> s/xbzrle-bytes/transferred-bytes
>>>
>>>> +#
>>>> +# @xbzrle-pages: @optional, amount of pages transferred to the target VM
>>>> +# only returned when migration is active or completed
>>>
>>> s/xbzrle-pages/transferred-pages
>>>
>>>> +#
>>>> +# @xbzrle-cache-miss: @optional, number of cache miss
>>>> +# only returned when migration is active or completed
>>>
>>> s/xbzrle/xbzrle//
>>>
>>>> +#
>>>> +# @xbzrle-overflow: @optional, number of overflows
>>>> +# only returned when migration is active or completed
>>>
>>> s/xbzrle///
>>>
>>> Besides, all these parameters shouldn't be optional as they are unconditionally
>>> included (BZRLECacheStats itself is optional as returned by query-migrate).
>>>
>>>> +#
>>>> +# Since: 1.2
>>>> +##
>>>> +{ 'type': 'XBZRLECacheStats',
>>>> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
>>>> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
>>>> +
>>>> +##
>>>> # @MigrationInfo
>>>> #
>>>> # Information about current migration process.
>>>> @@ -292,11 +317,16 @@
>>>> # status, only returned if status is 'active' and it is a block
>>>> # migration
>>>> #
>>>> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
>>>> +# migration statistics, only returned if XBZRLE feature is on
>>>> +# (since 1.2)
>>>> +#
>>>> # Since: 0.14.0
>>>> ##
>>>> { 'type': 'MigrationInfo',
>>>> 'data': {'*status': 'str', '*ram': 'MigrationStats',
>>>> - '*disk': 'MigrationStats'} }
>>>> + '*disk': 'MigrationStats',
>>>> + '*xbzrle-cache': 'XBZRLECacheStats'} }
>>>>
>>>> ##
>>>> # @query-migrate
>>>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>>>> index a5a67eb..0546f42 100644
>>>> --- a/qmp-commands.hx
>>>> +++ b/qmp-commands.hx
>>>> @@ -2106,6 +2106,17 @@ The main json-object contains the following:
>>>> - "transferred": amount transferred (json-int)
>>>> - "remaining": amount remaining (json-int)
>>>> - "total": total (json-int)
>>>> +- "xbzrle-cache": only present if XBZRLE is active.
>>>> + It is a json-object with the following XBZRLE information:
>>>> + - "cache-size": XBZRLE cache size
>>>> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
>>>> + status is "active" or "completed"
>>>> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
>>>> + status is "active" or "completed"
>>>> + - "cache-miss": number of cache misses, only present if
>>>> + status is "active" or "completed"
>>>> + - "overflow": number of XBZRLE overflows, only present if
>>>> + status is "active" or "completed"
>>>> Examples:
>>>>
>>>> 1. Before the first migration
>>>> @@ -2170,6 +2181,30 @@ Examples:
>>>> }
>>>> }
>>>>
>>>> +6. Migration is being performed and XBZRLE is active:
>>>> +
>>>> +-> { "execute": "query-migrate" }
>>>> +<- {
>>>> + "return":{
>>>> + "status":"active",
>>>> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
>>>> + "ram":{
>>>> + "total":1057024,
>>>> + "remaining":1053304,
>>>> + "transferred":3720,
>>>> + "duplicate": 10,
>>>> + "normal" : 3333
>>>> + },
>>>> + "cache":{
>>>> + "cache-size": 1024
>>>> + "xbzrle-transferred":20971520,
>>>> + "xbzrle-pages":2444343,
>>>> + "xbzrle-cache-miss":2244,
>>>> + "xbzrle-overflow":34434
>>>> + }
>>>> + }
>>>> + }
>>>> +
>>>> EQMP
>>>>
>>>> {
>>>
>>
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-31 14:13 ` Orit Wasserman
@ 2012-07-31 15:54 ` Luiz Capitulino
0 siblings, 0 replies; 31+ messages in thread
From: Luiz Capitulino @ 2012-07-31 15:54 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel,
Benoit Hudzia, mdroth, blauwirbel, Petter Svard, chegu_vinod, avi,
Aidan Shribman, pbonzini, eblake
On Tue, 31 Jul 2012 17:13:46 +0300
Orit Wasserman <owasserm@redhat.com> wrote:
> On 07/31/2012 04:16 PM, Luiz Capitulino wrote:
> > On Tue, 31 Jul 2012 11:31:09 +0300
> > Orit Wasserman <owasserm@redhat.com> wrote:
> >
> >> On 07/30/2012 10:37 PM, Luiz Capitulino wrote:
> >>> On Sun, 29 Jul 2012 12:43:02 +0300
> >>> Orit Wasserman <owasserm@redhat.com> wrote:
> >>>
> >>>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> >>>> Signed-off-by: Petter Svard <petters@cs.umu.se>
> >>>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> >>>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> >>>> Signed-off-by: Juan Quintela <quintela@redhat.com>
> >>>> ---
> >>>> arch_init.c | 28 ++++++++++++++++++++++++++++
> >>>> hmp.c | 21 +++++++++++++++++++++
> >>>> migration.c | 28 ++++++++++++++++++++++++++++
> >>>> migration.h | 4 ++++
> >>>> qapi-schema.json | 32 +++++++++++++++++++++++++++++++-
> >>>> qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
> >>>> 6 files changed, 147 insertions(+), 1 deletions(-)
> >>>>
> >>>> diff --git a/arch_init.c b/arch_init.c
> >>>> index 7f12317..9833d54 100644
> >>>> --- a/arch_init.c
> >>>> +++ b/arch_init.c
> >>>> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
> >>>> typedef struct AccountingInfo {
> >>>> uint64_t dup_pages;
> >>>> uint64_t norm_pages;
> >>>> + uint64_t xbzrle_bytes;
> >>>> + uint64_t xbzrle_pages;
> >>>> + uint64_t xbzrle_cache_miss;
> >>>> uint64_t iterations;
> >>>> + uint64_t xbzrle_overflows;
> >>>> } AccountingInfo;
> >>>>
> >>>> static AccountingInfo acct_info;
> >>>> @@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
> >>>> return acct_info.norm_pages;
> >>>> }
> >>>>
> >>>> +uint64_t xbzrle_mig_bytes_transferred(void)
> >>>> +{
> >>>> + return acct_info.xbzrle_bytes;
> >>>> +}
> >>>> +
> >>>> +uint64_t xbzrle_mig_pages_transferred(void)
> >>>> +{
> >>>> + return acct_info.xbzrle_pages;
> >>>> +}
> >>>> +
> >>>> +uint64_t xbzrle_mig_pages_cache_miss(void)
> >>>> +{
> >>>> + return acct_info.xbzrle_cache_miss;
> >>>> +}
> >>>> +
> >>>> +uint64_t xbzrle_mig_pages_overflow(void)
> >>>> +{
> >>>> + return acct_info.xbzrle_overflows;
> >>>> +}
> >>>> +
> >>>> static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
> >>>> int cont, int flag)
> >>>> {
> >>>> @@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >>>> if (!cache_is_cached(XBZRLE.cache, current_addr)) {
> >>>> cache_insert(XBZRLE.cache, current_addr,
> >>>> g_memdup(current_data, TARGET_PAGE_SIZE));
> >>>> + acct_info.xbzrle_cache_miss++;
> >>>> return -1;
> >>>> }
> >>>>
> >>>> @@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >>>> return 0;
> >>>> } else if (encoded_len == -1) {
> >>>> DPRINTF("Overflow\n");
> >>>> + acct_info.xbzrle_overflows++;
> >>>> /* update data in the cache */
> >>>> memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
> >>>> return -1;
> >>>> @@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
> >>>> qemu_put_be16(f, encoded_len);
> >>>> qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
> >>>> bytes_sent = encoded_len + 1 + 2;
> >>>> + acct_info.xbzrle_pages++;
> >>>> + acct_info.xbzrle_bytes += bytes_sent;
> >>>>
> >>>> return bytes_sent;
> >>>> }
> >>>> diff --git a/hmp.c b/hmp.c
> >>>> index 9770d7b..383d5b1 100644
> >>>> --- a/hmp.c
> >>>> +++ b/hmp.c
> >>>> @@ -172,6 +172,27 @@ void hmp_info_migrate(Monitor *mon)
> >>>> info->disk->total >> 10);
> >>>> }
> >>>>
> >>>> + if (info->has_xbzrle_cache) {
> >>>> + monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
> >>>> + info->xbzrle_cache->cache_size);
> >>>> + if (info->xbzrle_cache->has_xbzrle_bytes) {
> >>>> + monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
> >>>> + info->xbzrle_cache->xbzrle_bytes >> 10);
> >>>> + }
> >>>> + if (info->xbzrle_cache->has_xbzrle_pages) {
> >>>> + monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
> >>>> + info->xbzrle_cache->xbzrle_pages);
> >>>> + }
> >>>> + if (info->xbzrle_cache->has_xbzrle_cache_miss) {
> >>>> + monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
> >>>> + info->xbzrle_cache->xbzrle_cache_miss);
> >>>> + }
> >>>> + if (info->xbzrle_cache->has_xbzrle_overflow) {
> >>>> + monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
> >>>> + info->xbzrle_cache->xbzrle_overflow);
> >>>> + }
> >>>> + }
> >>>> +
> >>>> qapi_free_MigrationInfo(info);
> >>>> qapi_free_MigrationParameters(params);
> >>>> }
> >>>> diff --git a/migration.c b/migration.c
> >>>> index 4dc99ba..fb802bc 100644
> >>>> --- a/migration.c
> >>>> +++ b/migration.c
> >>>> @@ -136,6 +136,23 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> >>>> return params;
> >>>> }
> >>>>
> >>>> +static void get_xbzrle_cache_stats(MigrationInfo *info)
> >>>> +{
> >>>> + if (migrate_use_xbzrle()) {
> >>>> + info->has_xbzrle_cache = true;
> >>>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> >>>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> >>>> + info->xbzrle_cache->has_xbzrle_bytes = true;
> >>>> + info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
> >>>> + info->xbzrle_cache->has_xbzrle_pages = true;
> >>>> + info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
> >>>> + info->xbzrle_cache->has_xbzrle_cache_miss = true;
> >>>> + info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
> >>>> + info->xbzrle_cache->has_xbzrle_overflow = true;
> >>>> + info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
> >>>> + }
> >>>> +}
> >>>> +
> >>>> MigrationInfo *qmp_query_migrate(Error **errp)
> >>>> {
> >>>> MigrationInfo *info = g_malloc0(sizeof(*info));
> >>>> @@ -144,6 +161,13 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> >>>> switch (s->state) {
> >>>> case MIG_STATE_SETUP:
> >>>> /* no migration has happened ever */
> >>>> +
> >>>> + /* display xbzrle cache size */
> >>>> + if (migrate_use_xbzrle()) {
> >>>> + info->has_xbzrle_cache = true;
> >>>> + info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
> >>>> + info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
> >>>> + }
> >>>
> >>> Is it really useful to return this in MIG_SETUP? Can't the cache size
> >>> be queried by some query- command?
> >> I like it this way and it is very simple to use, you need to use query-migrate command if you do migration
> >> anyway.
> >
> > But this will only be returned before a migration takes place. Then it will
> > never be returned again. Doesn't seem to be the right place for it.
> It is returned also in MIG_ACTIVE and MIG_COMPLETE (when XBZRLE are active).
That's fine.
> >
> >> Otherwise we will need to add a query command for each configurable parameters,
> >> so one for speed and another for downtime and probably more in the future.
> >
> > I don't think this is a problem. We're trying to design QMP commands as we
> > would design a C API, and I'd have different functions to query different things.
> >
> > Besides, let's not mix what's best to a human user and what's best for a
> > machine protocol. If we add different query commands for different parameters,
> > then it's possible to call them from 'info migrate' if you wish.
> sounds reasonable, I will change it.
>
> Orit
> >
> >> This way we use one command to query the migration setup.
> >
> > Again, that information would only be returned before a first migration
> > occurs.
> >
> >>
> >> Orit
> >>>
> >>>> break;
> >>>> case MIG_STATE_ACTIVE:
> >>>> info->has_status = true;
> >>>> @@ -166,8 +190,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
> >>>> info->disk->remaining = blk_mig_bytes_remaining();
> >>>> info->disk->total = blk_mig_bytes_total();
> >>>> }
> >>>> +
> >>>> + get_xbzrle_cache_stats(info);
> >>>> break;
> >>>> case MIG_STATE_COMPLETED:
> >>>> + get_xbzrle_cache_stats(info);
> >>>> +
> >>>> info->has_status = true;
> >>>> info->status = g_strdup("completed");
> >>>>
> >>>> diff --git a/migration.h b/migration.h
> >>>> index e4a7cd7..a9852fc 100644
> >>>> --- a/migration.h
> >>>> +++ b/migration.h
> >>>> @@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
> >>>> uint64_t dup_mig_pages_transferred(void);
> >>>> uint64_t norm_mig_bytes_transferred(void);
> >>>> uint64_t norm_mig_pages_transferred(void);
> >>>> +uint64_t xbzrle_mig_bytes_transferred(void);
> >>>> +uint64_t xbzrle_mig_pages_transferred(void);
> >>>> +uint64_t xbzrle_mig_pages_overflow(void);
> >>>> +uint64_t xbzrle_mig_pages_cache_miss(void);
> >>>>
> >>>> /**
> >>>> * @migrate_add_blocker - prevent migration from proceeding
> >>>> diff --git a/qapi-schema.json b/qapi-schema.json
> >>>> index a936714..91dee72 100644
> >>>> --- a/qapi-schema.json
> >>>> +++ b/qapi-schema.json
> >>>> @@ -275,6 +275,31 @@
> >>>> 'total_time': 'int', 'duplicate': 'int', 'normal': 'int' } }
> >>>>
> >>>> ##
> >>>> +# @XBZRLECacheStats
> >>>> +#
> >>>> +# Detailed XBZRLE migration cache statistics
> >>>> +#
> >>>> +# @cache-size: XBZRLE cache size
> >>>> +#
> >>>> +# @xbzrle-bytes: @optional, amount of bytes already transferred to the target VM
> >>>> +# only returned when migration is active or completed
> >>>
> >>> s/xbzrle-bytes/transferred-bytes
> >>>
> >>>> +#
> >>>> +# @xbzrle-pages: @optional, amount of pages transferred to the target VM
> >>>> +# only returned when migration is active or completed
> >>>
> >>> s/xbzrle-pages/transferred-pages
> >>>
> >>>> +#
> >>>> +# @xbzrle-cache-miss: @optional, number of cache miss
> >>>> +# only returned when migration is active or completed
> >>>
> >>> s/xbzrle/xbzrle//
> >>>
> >>>> +#
> >>>> +# @xbzrle-overflow: @optional, number of overflows
> >>>> +# only returned when migration is active or completed
> >>>
> >>> s/xbzrle///
> >>>
> >>> Besides, all these parameters shouldn't be optional as they are unconditionally
> >>> included (BZRLECacheStats itself is optional as returned by query-migrate).
> >>>
> >>>> +#
> >>>> +# Since: 1.2
> >>>> +##
> >>>> +{ 'type': 'XBZRLECacheStats',
> >>>> + 'data': {'cache-size': 'int', '*xbzrle-bytes': 'int', '*xbzrle-pages': 'int',
> >>>> + '*xbzrle-cache-miss': 'int', '*xbzrle-overflow': 'int' } }
> >>>> +
> >>>> +##
> >>>> # @MigrationInfo
> >>>> #
> >>>> # Information about current migration process.
> >>>> @@ -292,11 +317,16 @@
> >>>> # status, only returned if status is 'active' and it is a block
> >>>> # migration
> >>>> #
> >>>> +# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
> >>>> +# migration statistics, only returned if XBZRLE feature is on
> >>>> +# (since 1.2)
> >>>> +#
> >>>> # Since: 0.14.0
> >>>> ##
> >>>> { 'type': 'MigrationInfo',
> >>>> 'data': {'*status': 'str', '*ram': 'MigrationStats',
> >>>> - '*disk': 'MigrationStats'} }
> >>>> + '*disk': 'MigrationStats',
> >>>> + '*xbzrle-cache': 'XBZRLECacheStats'} }
> >>>>
> >>>> ##
> >>>> # @query-migrate
> >>>> diff --git a/qmp-commands.hx b/qmp-commands.hx
> >>>> index a5a67eb..0546f42 100644
> >>>> --- a/qmp-commands.hx
> >>>> +++ b/qmp-commands.hx
> >>>> @@ -2106,6 +2106,17 @@ The main json-object contains the following:
> >>>> - "transferred": amount transferred (json-int)
> >>>> - "remaining": amount remaining (json-int)
> >>>> - "total": total (json-int)
> >>>> +- "xbzrle-cache": only present if XBZRLE is active.
> >>>> + It is a json-object with the following XBZRLE information:
> >>>> + - "cache-size": XBZRLE cache size
> >>>> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
> >>>> + status is "active" or "completed"
> >>>> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
> >>>> + status is "active" or "completed"
> >>>> + - "cache-miss": number of cache misses, only present if
> >>>> + status is "active" or "completed"
> >>>> + - "overflow": number of XBZRLE overflows, only present if
> >>>> + status is "active" or "completed"
> >>>> Examples:
> >>>>
> >>>> 1. Before the first migration
> >>>> @@ -2170,6 +2181,30 @@ Examples:
> >>>> }
> >>>> }
> >>>>
> >>>> +6. Migration is being performed and XBZRLE is active:
> >>>> +
> >>>> +-> { "execute": "query-migrate" }
> >>>> +<- {
> >>>> + "return":{
> >>>> + "status":"active",
> >>>> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
> >>>> + "ram":{
> >>>> + "total":1057024,
> >>>> + "remaining":1053304,
> >>>> + "transferred":3720,
> >>>> + "duplicate": 10,
> >>>> + "normal" : 3333
> >>>> + },
> >>>> + "cache":{
> >>>> + "cache-size": 1024
> >>>> + "xbzrle-transferred":20971520,
> >>>> + "xbzrle-pages":2444343,
> >>>> + "xbzrle-cache-miss":2244,
> >>>> + "xbzrle-overflow":34434
> >>>> + }
> >>>> + }
> >>>> + }
> >>>> +
> >>>> EQMP
> >>>>
> >>>> {
> >>>
> >>
> >
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-07-31 18:54 [Qemu-devel] [PATCH 00/11] Migration next v8 Orit Wasserman
@ 2012-07-31 18:54 ` Orit Wasserman
0 siblings, 0 replies; 31+ messages in thread
From: Orit Wasserman @ 2012-07-31 18:54 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, aliguori, quintela, Petter Svard, stefanha, mdroth,
Benoit Hudzia, lcapitulino, blauwirbel, Orit Wasserman,
chegu_vinod, avi, Aidan Shribman, pbonzini, eblake
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 13 +++++++++++++
migration.c | 17 +++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 28 +++++++++++++++++++++++++++-
qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
6 files changed, 124 insertions(+), 1 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 7f12317..9833d54 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index f19a63b..a05145a 100644
--- a/hmp.c
+++ b/hmp.c
@@ -177,6 +177,19 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->xbzrle_bytes >> 10);
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->xbzrle_pages);
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_cache_miss);
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_overflow);
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationCapabilityStatusList(caps);
}
diff --git a/migration.c b/migration.c
index 9e3b17a..a506bbb 100644
--- a/migration.c
+++ b/migration.c
@@ -136,6 +136,19 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
return caps;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -167,8 +180,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index e0832ea..e7cfb78 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -278,6 +278,27 @@
'normal-bytes': 'int' } }
##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @xbzrle-bytes: amount of bytes already transferred to the target VM
+#
+# @xbzrle-pages: amount of pages transferred to the target VM
+#
+# @xbzrle-cache-miss: @optional, number of cache miss
+#
+# @xbzrle-overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', 'xbzrle-bytes': 'int', 'xbzrle-pages': 'int',
+ 'xbzrle-cache-miss': 'int', 'xbzrle-overflow': 'int' } }
+
+##
# @MigrationInfo
#
# Information about current migration process.
@@ -295,11 +316,16 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on and
+# status is 'active' or 'completed' (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f1bbbda..a5b35b0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2128,6 +2128,17 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
+ status is "active" or "completed"
+ - "xbzrle-pages": number of XBZRLE compressed pages, only present if
+ status is "active" or "completed"
+ - "cache-miss": number of cache misses, only present if
+ status is "active" or "completed"
+ - "overflow": number of XBZRLE overflows, only present if
+ status is "active" or "completed"
Examples:
1. Before the first migration
@@ -2195,6 +2206,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal" : 3333
+ },
+ "cache":{
+ "cache-size": 1024
+ "xbzrle-transferred":20971520,
+ "xbzrle-pages":2444343,
+ "xbzrle-cache-miss":2244,
+ "xbzrle-overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PULL 00/11] Migration next
@ 2012-08-01 18:01 Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 01/11] Add migration capabilities Juan Quintela
` (11 more replies)
0 siblings, 12 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel
Hi
Here is the xbzrle pull request. All comments about QMP names addressed.
Please, pull
The following changes since commit 02d2bd5d57812154cfb978bc2098cf49d551583d:
Replace 'struct siginfo' with 'siginfo_t'. (2012-08-01 08:54:07 -0500)
are available in the git repository at:
http://repo.or.cz/r/qemu/quintela.git migration-next-20120801
for you to fetch changes up to 7bff472b8fba64b7417c243d2132422afc0c2137:
Restart optimization on stage3 update version (2012-08-01 19:56:57 +0200)
Juan Quintela (1):
Restart optimization on stage3 update version
Orit Wasserman (10):
Add migration capabilities
Add migrate-set-capabilities and query-migrate-capabilities
Add XBZRLE documentation
Add cache handling functions
Add uleb encoding/decoding functions
Add xbzrle_encode_buffer and xbzrle_decode_buffer functions
Add XBZRLE to ram_save_block and ram_save_live
Add migrate_set_cachesize command
Add migration accounting for normal and duplicate pages
Add XBZRLE statistics
Makefile.objs | 1 +
arch_init.c | 246 +++++++++++++++++++++++++++++++++++++++++++++-
cutils.c | 42 ++++++++
docs/xbzrle.txt | 136 +++++++++++++++++++++++++
hmp-commands.hx | 40 ++++++++
hmp.c | 124 +++++++++++++++++++++++
hmp.h | 5 +
include/qemu/page_cache.h | 79 +++++++++++++++
migration.c | 124 +++++++++++++++++++++++
migration.h | 21 ++++
monitor.c | 21 ++++
page_cache.c | 218 ++++++++++++++++++++++++++++++++++++++++
qapi-schema.json | 137 +++++++++++++++++++++++++-
qemu-common.h | 21 ++++
qmp-commands.hx | 180 ++++++++++++++++++++++++++++++++-
savevm.c | 159 ++++++++++++++++++++++++++++++
16 files changed, 1542 insertions(+), 12 deletions(-)
create mode 100644 docs/xbzrle.txt
create mode 100644 include/qemu/page_cache.h
create mode 100644 page_cache.c
--
1.7.11.2
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 01/11] Add migration capabilities
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 02/11] Add migrate-set-capabilities and query-migrate-capabilities Juan Quintela
` (10 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman
From: Orit Wasserman <owasserm@redhat.com>
Add migration capabilities that can be queried by the management using
query-migration-supported-capabilities command.
The management can query the source QEMU and the destination QEMU in order to
verify both support some migration capability (currently only XBZRLE).
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
hmp-commands.hx | 2 ++
hmp.c | 21 +++++++++++++++++++++
hmp.h | 1 +
migration.c | 12 ++++++++++++
monitor.c | 7 +++++++
qapi-schema.json | 39 +++++++++++++++++++++++++++++++++++++++
qmp-commands.hx | 25 +++++++++++++++++++++++++
7 files changed, 107 insertions(+)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index eea8b32..8267237 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1417,6 +1417,8 @@ show CPU statistics
show user network stack connection states
@item info migrate
show migration status
+@item info migration_supported_capabilities
+show migration supported capabilities
@item info balloon
show balloon information
@item info qtree
diff --git a/hmp.c b/hmp.c
index 6b72a64..2ff71a3 100644
--- a/hmp.c
+++ b/hmp.c
@@ -161,6 +161,27 @@ void hmp_info_migrate(Monitor *mon)
qapi_free_MigrationInfo(info);
}
+void hmp_info_migration_supported_capabilities(Monitor *mon)
+{
+ MigrationCapabilityStatusList *caps_list, *cap;
+
+ caps_list = qmp_query_migration_supported_capabilities(NULL);
+ if (!caps_list) {
+ monitor_printf(mon, "No supported migration capabilities found\n");
+ return;
+ }
+
+ for (cap = caps_list; cap; cap = cap->next) {
+ monitor_printf(mon, "%s: %s ",
+ MigrationCapability_lookup[cap->value->capability],
+ cap->value->state ? "on" : "off");
+ }
+
+ monitor_printf(mon, "\n");
+
+ qapi_free_MigrationCapabilityStatusList(caps_list);
+}
+
void hmp_info_cpus(Monitor *mon)
{
CpuInfoList *cpu_list, *cpu;
diff --git a/hmp.h b/hmp.h
index 8d2b0d7..8442c22 100644
--- a/hmp.h
+++ b/hmp.h
@@ -25,6 +25,7 @@ void hmp_info_uuid(Monitor *mon);
void hmp_info_chardev(Monitor *mon);
void hmp_info_mice(Monitor *mon);
void hmp_info_migrate(Monitor *mon);
+void hmp_info_migration_supported_capabilities(Monitor *mon);
void hmp_info_cpus(Monitor *mon);
void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
diff --git a/migration.c b/migration.c
index 8db1b43..35444f7 100644
--- a/migration.c
+++ b/migration.c
@@ -166,6 +166,18 @@ MigrationInfo *qmp_query_migrate(Error **errp)
return info;
}
+MigrationCapabilityStatusList *
+qmp_query_migration_supported_capabilities(Error **errp)
+{
+ MigrationCapabilityStatusList *caps_list = g_malloc0(sizeof(*caps_list));
+
+ caps_list->value = g_malloc(sizeof(*caps_list->value));
+ caps_list->value->capability = MIGRATION_CAPABILITY_XBZRLE;
+ caps_list->next = NULL;
+
+ return caps_list;
+}
+
/* shared migration helpers */
static int migrate_fd_cleanup(MigrationState *s)
diff --git a/monitor.c b/monitor.c
index 49dccfe..bb55168 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2655,6 +2655,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_migrate,
},
{
+ .name = "migration_supported_capabilities",
+ .args_type = "",
+ .params = "",
+ .help = "show migration supported capabilities",
+ .mhandler.info = hmp_info_migration_supported_capabilities,
+ },
+ {
.name = "balloon",
.args_type = "",
.params = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index bc55ed2..9d4107b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -306,6 +306,45 @@
{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
##
+# @MigrationCapability
+#
+# Migration capabilities enumeration
+#
+# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length Encoding).
+# This feature allows us to minimize migration traffic for certain work
+# loads, by sending compressed difference of the pages
+#
+# Since: 1.2
+##
+{ 'enum': 'MigrationCapability',
+ 'data': ['xbzrle'] }
+
+##
+# @MigrationCapabilityStatus
+#
+# Migration capability information
+#
+# @capability: capability enum
+#
+# @state: capability state bool
+#
+# Since: 1.2
+##
+{ 'type': 'MigrationCapabilityStatus',
+ 'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
+
+##
+# @query-migration-supported-capabilities
+#
+# Returns information about current migration process capabilities.
+#
+# Returns: @MigrationCapabilityStatus list
+#
+# Since: 1.2
+##
+{ 'command': 'query-migration-supported-capabilities', 'returns': ['MigrationCapabilityStatus'] }
+
+##
# @MouseInfo:
#
# Information about a mouse device.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e3cf3c5..16fbcef 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2141,6 +2141,31 @@ EQMP
},
SQMP
+query-migration-supported-capabilities
+-------
+
+Query migration supported capabilities
+
+- "xbzrle": xbzrle support
+
+Arguments:
+
+Example:
+
+-> { "execute": "query-migration-supported-capabilities"}
+<- { "return": [ { "capability": "xbzrle", "state": true },
+ { "capability": "foobar", "state": false } ] }
+
+EQMP
+
+ {
+ .name = "query-migration-supported-capabilities",
+ .args_type = "",
+ .mhandler.cmd_new =
+ qmp_marshal_input_query_migration_supported_capabilities,
+ },
+
+SQMP
query-balloon
-------------
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 02/11] Add migrate-set-capabilities and query-migrate-capabilities
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 01/11] Add migration capabilities Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 03/11] Add XBZRLE documentation Juan Quintela
` (9 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman
From: Orit Wasserman <owasserm@redhat.com>
The management can enable/disable a capability for the next migration by using
migrate-set-apabilities QMP command.
The management can query the current migration capabilities using
query-migrate-capabilities QMP command.
The user can use migrate_set_capability and 'info migrate_capabilities' HMP
commands.
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
hmp-commands.hx | 16 ++++++++++++++
hmp.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hmp.h | 2 ++
migration.c | 46 +++++++++++++++++++++++++++++++++++++++
migration.h | 2 ++
monitor.c | 7 ++++++
qapi-schema.json | 32 ++++++++++++++++++++++++++++
qmp-commands.hx | 49 ++++++++++++++++++++++++++++++++++++++++++
8 files changed, 219 insertions(+)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8267237..f4c8495 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -861,6 +861,20 @@ Set maximum tolerated downtime (in seconds) for migration.
ETEXI
{
+ .name = "migrate_set_capability",
+ .args_type = "capability:s,state:b",
+ .params = "capability state",
+ .help = "Enable/Disable the usage of a capability for migration",
+ .mhandler.cmd = hmp_migrate_set_capability,
+ },
+
+STEXI
+@item migrate_set_capability @var{capability} @var{state}
+@findex migrate_set_capability
+Enable/Disable the usage of a capability @var{capability} for migration.
+ETEXI
+
+ {
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
@@ -1419,6 +1433,8 @@ show user network stack connection states
show migration status
@item info migration_supported_capabilities
show migration supported capabilities
+@item info migrate_capabilities
+show current migration capabilities
@item info balloon
show balloon information
@item info qtree
diff --git a/hmp.c b/hmp.c
index 2ff71a3..463b730 100644
--- a/hmp.c
+++ b/hmp.c
@@ -131,8 +131,21 @@ void hmp_info_mice(Monitor *mon)
void hmp_info_migrate(Monitor *mon)
{
MigrationInfo *info;
+ MigrationCapabilityStatusList *caps, *cap;
info = qmp_query_migrate(NULL);
+ caps = qmp_query_migrate_capabilities(NULL);
+
+ /* do not display parameters during setup */
+ if (info->has_status && caps) {
+ monitor_printf(mon, "capabilities: ");
+ for (cap = caps; cap; cap = cap->next) {
+ monitor_printf(mon, "%s: %s ",
+ MigrationCapability_lookup[cap->value->capability],
+ cap->value->state ? "on" : "off");
+ }
+ monitor_printf(mon, "\n");
+ }
if (info->has_status) {
monitor_printf(mon, "Migration status: %s\n", info->status);
@@ -159,6 +172,7 @@ void hmp_info_migrate(Monitor *mon)
}
qapi_free_MigrationInfo(info);
+ qapi_free_MigrationCapabilityStatusList(caps);
}
void hmp_info_migration_supported_capabilities(Monitor *mon)
@@ -182,6 +196,25 @@ void hmp_info_migration_supported_capabilities(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps_list);
}
+void hmp_info_migrate_capabilities(Monitor *mon)
+{
+ MigrationCapabilityStatusList *caps, *cap;
+
+ caps = qmp_query_migrate_capabilities(NULL);
+
+ if (caps) {
+ monitor_printf(mon, "capabilities: ");
+ for (cap = caps; cap; cap = cap->next) {
+ monitor_printf(mon, "%s: %s ",
+ MigrationCapability_lookup[cap->value->capability],
+ cap->value->state ? "on" : "off");
+ }
+ monitor_printf(mon, "\n");
+ }
+
+ qapi_free_MigrationCapabilityStatusList(caps);
+}
+
void hmp_info_cpus(Monitor *mon)
{
CpuInfoList *cpu_list, *cpu;
@@ -756,6 +789,38 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
qmp_migrate_set_speed(value, NULL);
}
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
+{
+ const char *cap = qdict_get_str(qdict, "capability");
+ bool state = qdict_get_bool(qdict, "state");
+ Error *err = NULL;
+ MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
+ int i;
+
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
+ caps->value = g_malloc0(sizeof(*caps->value));
+ caps->value->capability = i;
+ caps->value->state = state;
+ caps->next = NULL;
+ qmp_migrate_set_capabilities(caps, &err);
+ break;
+ }
+ }
+
+ if (i == MIGRATION_CAPABILITY_MAX) {
+ error_set(&err, QERR_INVALID_PARAMETER, cap);
+ }
+
+ qapi_free_MigrationCapabilityStatusList(caps);
+
+ if (err) {
+ monitor_printf(mon, "migrate_set_parameter: %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ }
+}
+
void hmp_set_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
diff --git a/hmp.h b/hmp.h
index 8442c22..f2a890f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -26,6 +26,7 @@ void hmp_info_chardev(Monitor *mon);
void hmp_info_mice(Monitor *mon);
void hmp_info_migrate(Monitor *mon);
void hmp_info_migration_supported_capabilities(Monitor *mon);
+void hmp_info_migrate_capabilities(Monitor *mon);
void hmp_info_cpus(Monitor *mon);
void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
@@ -52,6 +53,7 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
void hmp_set_password(Monitor *mon, const QDict *qdict);
void hmp_expire_password(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
diff --git a/migration.c b/migration.c
index 35444f7..d1a8d3a 100644
--- a/migration.c
+++ b/migration.c
@@ -113,6 +113,30 @@ uint64_t migrate_max_downtime(void)
return max_downtime;
}
+MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
+{
+ MigrationCapabilityStatusList *head = NULL;
+ MigrationCapabilityStatusList *caps;
+ MigrationState *s = migrate_get_current();
+ int i;
+
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ if (head == NULL) {
+ head = g_malloc0(sizeof(*caps));
+ caps = head;
+ } else {
+ caps->next = g_malloc0(sizeof(*caps));
+ caps = caps->next;
+ }
+ caps->value =
+ g_malloc(sizeof(*caps->value));
+ caps->value->capability = i;
+ caps->value->state = s->enabled_capabilities[i];
+ }
+
+ return head;
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -178,6 +202,22 @@ qmp_query_migration_supported_capabilities(Error **errp)
return caps_list;
}
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+ MigrationCapabilityStatusList *cap;
+
+ if (s->state == MIG_STATE_ACTIVE) {
+ error_set(errp, QERR_MIGRATION_ACTIVE);
+ return;
+ }
+
+ for (cap = params; cap; cap = cap->next) {
+ s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ }
+}
+
/* shared migration helpers */
static int migrate_fd_cleanup(MigrationState *s)
@@ -387,10 +427,16 @@ static MigrationState *migrate_init(const MigrationParams *params)
{
MigrationState *s = migrate_get_current();
int64_t bandwidth_limit = s->bandwidth_limit;
+ bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+
+ memcpy(enabled_capabilities, s->enabled_capabilities,
+ sizeof(enabled_capabilities));
memset(s, 0, sizeof(*s));
s->bandwidth_limit = bandwidth_limit;
s->params = *params;
+ memcpy(s->enabled_capabilities, enabled_capabilities,
+ sizeof(enabled_capabilities));
s->bandwidth_limit = bandwidth_limit;
s->state = MIG_STATE_SETUP;
diff --git a/migration.h b/migration.h
index 57572a6..713aae0 100644
--- a/migration.h
+++ b/migration.h
@@ -19,6 +19,7 @@
#include "notify.h"
#include "error.h"
#include "vmstate.h"
+#include "qapi-types.h"
struct MigrationParams {
bool blk;
@@ -39,6 +40,7 @@ struct MigrationState
void *opaque;
MigrationParams params;
int64_t total_time;
+ bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
};
void process_incoming_migration(QEMUFile *f);
diff --git a/monitor.c b/monitor.c
index bb55168..5c5233b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2662,6 +2662,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_migration_supported_capabilities,
},
{
+ .name = "migrate_capabilities",
+ .args_type = "",
+ .params = "",
+ .help = "show current migration capabilities",
+ .mhandler.info = hmp_info_migrate_capabilities,
+ },
+ {
.name = "balloon",
.args_type = "",
.params = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 9d4107b..b27611b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -345,6 +345,38 @@
{ 'command': 'query-migration-supported-capabilities', 'returns': ['MigrationCapabilityStatus'] }
##
+# @migrate-set-capabilities
+#
+# Enable/Disable the following migration capabilities (like xbzrle)
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-capabilities',
+ 'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
+
+##
+# @MigrationParameters
+#
+# @capabilities: @MigrationCapabilityStatus list contain current migration
+# capabilities status
+# Since: 1.2
+##
+{ 'type': 'MigrationParameters',
+ 'data': {'capabilities': ['MigrationCapabilityStatus']} }
+
+
+##
+# @query-migrate-capabilities
+#
+# Returns information about the current migration capabilities status
+#
+# Returns: @MigrationCapabilitiesStatus
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus']}
+
+##
# @MouseInfo:
#
# Information about a mouse device.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 16fbcef..e96a993 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2166,6 +2166,55 @@ EQMP
},
SQMP
+migrate-set-capabilities
+-------
+
+Enable/Disable migration capabilities
+
+- "xbzrle": xbzrle support
+
+Arguments:
+
+Example:
+
+-> { "execute": "migrate-set-capabilities" , "arguments":
+ { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
+
+EQMP
+
+ {
+ .name = "migrate_set_capabilities",
+ .args_type = "capabilities:O",
+ .params = "capability:s,state:b",
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_capabilities,
+ },
+SQMP
+query-migrate-capabilities
+-------
+
+Query current migration capabilities
+
+- "capabilities": migration capabilities state
+ - "xbzrle" : XBZRLE state (json-bool)
+
+Arguments:
+
+Example:
+
+-> { "execute": "query-migrate-capabilities" }
+<- { "return": {
+ "capabilities" : [ { "capability" : "xbzrle", "state" : false } ]
+ }
+ }
+EQMP
+
+ {
+ .name = "query-migrate-capabilities",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_migrate_capabilities,
+ },
+
+SQMP
query-balloon
-------------
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 03/11] Add XBZRLE documentation
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 01/11] Add migration capabilities Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 02/11] Add migrate-set-capabilities and query-migrate-capabilities Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 04/11] Add cache handling functions Juan Quintela
` (8 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman
From: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
docs/xbzrle.txt | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
create mode 100644 docs/xbzrle.txt
diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt
new file mode 100644
index 0000000..1463c0a
--- /dev/null
+++ b/docs/xbzrle.txt
@@ -0,0 +1,136 @@
+XBZRLE (Xor Based Zero Run Length Encoding)
+===========================================
+
+Using XBZRLE (Xor Based Zero Run Length Encoding) allows for the reduction
+of VM downtime and the total live-migration time of Virtual machines.
+It is particularly useful for virtual machines running memory write intensive
+workloads that are typical of large enterprise applications such as SAP ERP
+Systems, and generally speaking for any application that uses a sparse memory
+update pattern.
+
+Instead of sending the changed guest memory page this solution will send a
+compressed version of the updates, thus reducing the amount of data sent during
+live migration.
+In order to be able to calculate the update, the previous memory pages need to
+be stored on the source. Those pages are stored in a dedicated cache
+(hash table) and are
+accessed by their address.
+The larger the cache size the better the chances are that the page has already
+been stored in the cache.
+A small cache size will result in high cache miss rate.
+Cache size can be changed before and during migration.
+
+Format
+=======
+
+The compression format performs a XOR between the previous and current content
+of the page, where zero represents an unchanged value.
+The page data delta is represented by zero and non zero runs.
+A zero run is represented by its length (in bytes).
+A non zero run is represented by its length (in bytes) and the new data.
+The run length is encoded using ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+
+There can be more than one valid encoding, the sender may send a longer encoding
+for the benefit of reducing computation cost.
+
+page = zrun nzrun
+ | zrun nzrun page
+
+zrun = length
+
+nzrun = length byte...
+
+length = uleb128 encoded integer
+
+On the sender side XBZRLE is used as a compact delta encoding of page updates,
+retrieving the old page content from the cache (default size of 512 MB). The
+receiving side uses the existing page's content and XBZRLE to decode the new
+page's content.
+
+This work was originally based on research results published
+VEE 2011: Evaluation of Delta Compression Techniques for Efficient Live
+Migration of Large Virtual Machines by Benoit, Svard, Tordsson and Elmroth.
+Additionally the delta encoder XBRLE was improved further using the XBZRLE
+instead.
+
+XBZRLE has a sustained bandwidth of 2-2.5 GB/s for typical workloads making it
+ideal for in-line, real-time encoding such as is needed for live-migration.
+
+Example
+old buffer:
+1001 zeros
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 68 00 00 6b 00 6d
+3074 zeros
+
+new buffer:
+1001 zeros
+01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 68 00 00 67 00 69
+3074 zeros
+
+encoded buffer:
+
+encoded length 24
+e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
+
+Migration Capabilities
+======================
+In order to use XBZRLE the destination QEMU version should be able to
+decode the new format.
+Adding a new migration capabilities command that will allow external management
+to query for it support.
+A typical use for the destination
+ {qemu} info migrate_supported_capabilities
+ {qemu} xbzrle, ...
+
+In order to enable capabilities for future live migration,
+a new command migrate_set_capability is introduced:
+ {qemu} migrate_set_capability xbzrle
+
+Usage
+======
+
+1. Activate xbzrle
+2. Set the XBZRLE cache size - the cache size is in MBytes and should be a
+power of 2. The cache default value is 64MBytes.
+3. start outgoing migration
+
+A typical usage scenario:
+On the incoming QEMU:
+ {qemu} migrate_set_capability xbzrle on
+On the outgoing QEMU:
+ {qemu} migrate_set_capability xbzrle on
+ {qemu} migrate_set_cachesize 256m
+ {qemu} migrate -d tcp:destination.host:4444
+ {qemu} info migrate
+ ...
+ cache size: 67108864 bytes
+ transferred ram-duplicate: A kbytes
+ transferred ram-normal: B kbytes
+ transferred ram-xbrle: C kbytes
+ overflow ram-xbrle: D pages
+ cache-miss ram-xbrle: E pages
+
+cache-miss: the number of cache misses to date - high cache-miss rate
+indicates that the cache size is set too low.
+overflow: the number of overflows in the decoding which where the delta could
+not be compressed. This can happen if the changes in the pages are too large
+or there are many short changes; for example, changing every second byte (half a
+page).
+
+Testing: Testing indicated that live migration with XBZRLE was completed in 110
+seconds, whereas without it would not be able to complete.
+
+A simple synthetic memory r/w load generator:
+.. include <stdlib.h>
+.. include <stdio.h>
+.. int main()
+.. {
+.. char *buf = (char *) calloc(4096, 4096);
+.. while (1) {
+.. int i;
+.. for (i = 0; i < 4096 * 4; i++) {
+.. buf[i * 4096 / 4]++;
+.. }
+.. printf(".");
+.. }
+.. }
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 04/11] Add cache handling functions
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (2 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 03/11] Add XBZRLE documentation Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 05/11] Add uleb encoding/decoding functions Juan Quintela
` (7 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
Add MRU page cache mechanism.
The page are accessed by their address.
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
Makefile.objs | 1 +
cutils.c | 9 ++
include/qemu/page_cache.h | 79 +++++++++++++++++
page_cache.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++
qemu-common.h | 13 +++
5 files changed, 320 insertions(+)
create mode 100644 include/qemu/page_cache.h
create mode 100644 page_cache.c
diff --git a/Makefile.objs b/Makefile.objs
index 5ebbcfa..e0fb69b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -77,6 +77,7 @@ common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
+common-obj-y += page_cache.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_WIN32) += version.o
diff --git a/cutils.c b/cutils.c
index 9d4c570..35e2e2b 100644
--- a/cutils.c
+++ b/cutils.c
@@ -382,3 +382,12 @@ int qemu_parse_fd(const char *param)
}
return fd;
}
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value)
+{
+ if (!is_power_of_2(value)) {
+ value = 0x8000000000000000ULL >> clz64(value);
+ }
+ return value;
+}
diff --git a/include/qemu/page_cache.h b/include/qemu/page_cache.h
new file mode 100644
index 0000000..3839ac7
--- /dev/null
+++ b/include/qemu/page_cache.h
@@ -0,0 +1,79 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Orit Wasserman <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef PAGE_CACHE_H
+#define PAGE_CACHE_H
+
+/* Page cache for storing guest pages */
+typedef struct PageCache PageCache;
+
+/**
+ * cache_init: Initialize the page cache
+ *
+ *
+ * Returns new allocated cache or NULL on error
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: cache maximal number of cached pages
+ * @page_size: cache page size
+ */
+PageCache *cache_init(int64_t num_pages, unsigned int page_size);
+
+/**
+ * cache_fini: free all cache resources
+ * @cache pointer to the PageCache struct
+ */
+void cache_fini(PageCache *cache);
+
+/**
+ * cache_is_cached: Checks to see if the page is cached
+ *
+ * Returns %true if page is cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+bool cache_is_cached(const PageCache *cache, uint64_t addr);
+
+/**
+ * get_cached_data: Get the data cached for an addr
+ *
+ * Returns pointer to the data cached or NULL if not cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr);
+
+/**
+ * cache_insert: insert the page into the cache. the previous value will be overwritten
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page address
+ * @pdata: pointer to the page
+ */
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata);
+
+/**
+ * cache_resize: resize the page cache. In case of size reduction the extra
+ * pages will be freed
+ *
+ * Returns -1 on error new cache size on success
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: new page cache size (in pages)
+ */
+int64_t cache_resize(PageCache *cache, int64_t num_pages);
+
+#endif
diff --git a/page_cache.c b/page_cache.c
new file mode 100644
index 0000000..0294f7e
--- /dev/null
+++ b/page_cache.c
@@ -0,0 +1,218 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Orit Wasserman <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <strings.h>
+
+#include "qemu-common.h"
+#include "qemu/page_cache.h"
+
+#ifdef DEBUG_CACHE
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stdout, "cache: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+typedef struct CacheItem CacheItem;
+
+struct CacheItem {
+ uint64_t it_addr;
+ uint64_t it_age;
+ uint8_t *it_data;
+};
+
+struct PageCache {
+ CacheItem *page_cache;
+ unsigned int page_size;
+ int64_t max_num_items;
+ uint64_t max_item_age;
+ int64_t num_items;
+};
+
+PageCache *cache_init(int64_t num_pages, unsigned int page_size)
+{
+ int64_t i;
+
+ PageCache *cache;
+
+ if (num_pages <= 0) {
+ DPRINTF("invalid number of pages\n");
+ return NULL;
+ }
+
+ cache = g_malloc(sizeof(*cache));
+
+ /* round down to the nearest power of 2 */
+ if (!is_power_of_2(num_pages)) {
+ num_pages = pow2floor(num_pages);
+ DPRINTF("rounding down to %" PRId64 "\n", num_pages);
+ }
+ cache->page_size = page_size;
+ cache->num_items = 0;
+ cache->max_item_age = 0;
+ cache->max_num_items = num_pages;
+
+ DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items);
+
+ cache->page_cache = g_malloc((cache->max_num_items) *
+ sizeof(*cache->page_cache));
+
+ for (i = 0; i < cache->max_num_items; i++) {
+ cache->page_cache[i].it_data = NULL;
+ cache->page_cache[i].it_age = 0;
+ cache->page_cache[i].it_addr = -1;
+ }
+
+ return cache;
+}
+
+void cache_fini(PageCache *cache)
+{
+ int64_t i;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ for (i = 0; i < cache->max_num_items; i++) {
+ g_free(cache->page_cache[i].it_data);
+ }
+
+ g_free(cache->page_cache);
+ cache->page_cache = NULL;
+}
+
+static size_t cache_get_cache_pos(const PageCache *cache,
+ uint64_t address)
+{
+ size_t pos;
+
+ g_assert(cache->max_num_items);
+ pos = (address / cache->page_size) & (cache->max_num_items - 1);
+ return pos;
+}
+
+bool cache_is_cached(const PageCache *cache, uint64_t addr)
+{
+ size_t pos;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ pos = cache_get_cache_pos(cache, addr);
+
+ return (cache->page_cache[pos].it_addr == addr);
+}
+
+static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr)
+{
+ size_t pos;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ pos = cache_get_cache_pos(cache, addr);
+
+ return &cache->page_cache[pos];
+}
+
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr)
+{
+ return cache_get_by_addr(cache, addr)->it_data;
+}
+
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
+{
+
+ CacheItem *it = NULL;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ /* actual update of entry */
+ it = cache_get_by_addr(cache, addr);
+
+ if (!it->it_data) {
+ cache->num_items++;
+ }
+
+ it->it_data = pdata;
+ it->it_age = ++cache->max_item_age;
+ it->it_addr = addr;
+}
+
+int64_t cache_resize(PageCache *cache, int64_t new_num_pages)
+{
+ PageCache *new_cache;
+ int64_t i;
+
+ CacheItem *old_it, *new_it;
+
+ g_assert(cache);
+
+ /* cache was not inited */
+ if (cache->page_cache == NULL) {
+ return -1;
+ }
+
+ /* same size */
+ if (pow2floor(new_num_pages) == cache->max_num_items) {
+ return cache->max_num_items;
+ }
+
+ new_cache = cache_init(new_num_pages, cache->page_size);
+ if (!(new_cache)) {
+ DPRINTF("Error creating new cache\n");
+ return -1;
+ }
+
+ /* move all data from old cache */
+ for (i = 0; i < cache->max_num_items; i++) {
+ old_it = &cache->page_cache[i];
+ if (old_it->it_addr != -1) {
+ /* check for collision, if there is, keep MRU page */
+ new_it = cache_get_by_addr(new_cache, old_it->it_addr);
+ if (new_it->it_data) {
+ /* keep the MRU page */
+ if (new_it->it_age >= old_it->it_age) {
+ g_free(old_it->it_data);
+ } else {
+ g_free(new_it->it_data);
+ new_it->it_data = old_it->it_data;
+ new_it->it_age = old_it->it_age;
+ new_it->it_addr = old_it->it_addr;
+ }
+ } else {
+ cache_insert(new_cache, old_it->it_addr, old_it->it_data);
+ }
+ }
+ }
+
+ cache->page_cache = new_cache->page_cache;
+ cache->max_num_items = new_cache->max_num_items;
+ cache->num_items = new_cache->num_items;
+
+ g_free(new_cache);
+
+ return cache->max_num_items;
+}
diff --git a/qemu-common.h b/qemu-common.h
index d26ff39..432545b 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -1,3 +1,4 @@
+
/* Common header file that is included by all of qemu. */
#ifndef QEMU_COMMON_H
#define QEMU_COMMON_H
@@ -411,6 +412,18 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
/* Round number up to multiple */
#define QEMU_ALIGN_UP(n, m) QEMU_ALIGN_DOWN((n) + (m) - 1, (m))
+static inline bool is_power_of_2(uint64_t value)
+{
+ if (!value) {
+ return 0;
+ }
+
+ return !(value & (value - 1));
+}
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value);
+
#include "module.h"
#endif
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 05/11] Add uleb encoding/decoding functions
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (3 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 04/11] Add cache handling functions Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 06/11] Add xbzrle_encode_buffer and xbzrle_decode_buffer functions Juan Quintela
` (6 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman
From: Orit Wasserman <owasserm@redhat.com>
Implement Unsigned Little Endian Base 128.
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
cutils.c | 33 +++++++++++++++++++++++++++++++++
qemu-common.h | 8 ++++++++
2 files changed, 41 insertions(+)
diff --git a/cutils.c b/cutils.c
index 35e2e2b..ee4614d 100644
--- a/cutils.c
+++ b/cutils.c
@@ -391,3 +391,36 @@ int64_t pow2floor(int64_t value)
}
return value;
}
+
+/*
+ * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+int uleb128_encode_small(uint8_t *out, uint32_t n)
+{
+ g_assert(n <= 0x3fff);
+ if (n < 0x80) {
+ *out++ = n;
+ return 1;
+ } else {
+ *out++ = (n & 0x7f) | 0x80;
+ *out++ = n >> 7;
+ return 2;
+ }
+}
+
+int uleb128_decode_small(const uint8_t *in, uint32_t *n)
+{
+ if (!(*in & 0x80)) {
+ *n = *in++;
+ return 1;
+ } else {
+ *n = *in++ & 0x7f;
+ /* we exceed 14 bit number */
+ if (*in & 0x80) {
+ return -1;
+ }
+ *n |= *in++ << 7;
+ return 2;
+ }
+}
diff --git a/qemu-common.h b/qemu-common.h
index 432545b..b906b21 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -426,4 +426,12 @@ int64_t pow2floor(int64_t value);
#include "module.h"
+/*
+ * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+
+int uleb128_encode_small(uint8_t *out, uint32_t n);
+int uleb128_decode_small(const uint8_t *in, uint32_t *n);
+
#endif
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 06/11] Add xbzrle_encode_buffer and xbzrle_decode_buffer functions
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (4 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 05/11] Add uleb encoding/decoding functions Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 07/11] Add XBZRLE to ram_save_block and ram_save_live Juan Quintela
` (5 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel
Cc: Orit Wasserman, Benoit Hudzia, Eric Blake, Aidan Shribman,
Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
For performance we are encoding long word at a time.
For nzrun we use long-word-at-a-time NULL-detection tricks from strcmp():
using ((lword - 0x0101010101010101) & (~lword) & 0x8080808080808080) test
to find out if any byte in the long word is zero.
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
migration.h | 4 ++
savevm.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 163 insertions(+)
diff --git a/migration.h b/migration.h
index 713aae0..743c366 100644
--- a/migration.h
+++ b/migration.h
@@ -100,4 +100,8 @@ void migrate_add_blocker(Error *reason);
*/
void migrate_del_blocker(Error *reason);
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+ uint8_t *dst, int dlen);
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen);
+
#endif
diff --git a/savevm.c b/savevm.c
index 6e82b2d..0ea10c9 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2392,3 +2392,162 @@ void vmstate_register_ram_global(MemoryRegion *mr)
{
vmstate_register_ram(mr, NULL);
}
+
+/*
+ page = zrun nzrun
+ | zrun nzrun page
+
+ zrun = length
+
+ nzrun = length byte...
+
+ length = uleb128 encoded integer
+ */
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+ uint8_t *dst, int dlen)
+{
+ uint32_t zrun_len = 0, nzrun_len = 0;
+ int d = 0, i = 0;
+ long res, xor;
+ uint8_t *nzrun_start = NULL;
+
+ g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
+ sizeof(long)));
+
+ while (i < slen) {
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ res--;
+ }
+
+ /* word at a time for speed */
+ if (!res) {
+ while (i < slen &&
+ (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) {
+ i += sizeof(long);
+ zrun_len += sizeof(long);
+ }
+
+ /* go over the rest */
+ while (i < slen && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ }
+ }
+
+ /* buffer unchanged */
+ if (zrun_len == slen) {
+ return 0;
+ }
+
+ /* skip last zero run */
+ if (i == slen) {
+ return d;
+ }
+
+ d += uleb128_encode_small(dst + d, zrun_len);
+
+ zrun_len = 0;
+ nzrun_start = new_buf + i;
+
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] != new_buf[i]) {
+ i++;
+ nzrun_len++;
+ res--;
+ }
+
+ /* word at a time for speed, use of 32-bit long okay */
+ if (!res) {
+ /* truncation to 32-bit long okay */
+ long mask = 0x0101010101010101ULL;
+ while (i < slen) {
+ xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
+ if ((xor - mask) & ~xor & (mask << 7)) {
+ /* found the end of an nzrun within the current long */
+ while (old_buf[i] != new_buf[i]) {
+ nzrun_len++;
+ i++;
+ }
+ break;
+ } else {
+ i += sizeof(long);
+ nzrun_len += sizeof(long);
+ }
+ }
+ }
+
+ d += uleb128_encode_small(dst + d, nzrun_len);
+ /* overflow */
+ if (d + nzrun_len > dlen) {
+ return -1;
+ }
+ memcpy(dst + d, nzrun_start, nzrun_len);
+ d += nzrun_len;
+ nzrun_len = 0;
+ }
+
+ return d;
+}
+
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen)
+{
+ int i = 0, d = 0;
+ int ret;
+ uint32_t count = 0;
+
+ while (i < slen) {
+
+ /* zrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || (i && !count)) {
+ return -1;
+ }
+ i += ret;
+ d += count;
+
+ /* overflow */
+ if (d > dlen) {
+ return -1;
+ }
+
+ /* nzrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || !count) {
+ return -1;
+ }
+ i += ret;
+
+ /* overflow */
+ if (d + count > dlen || i + count > slen) {
+ return -1;
+ }
+
+ memcpy(dst + d, src + i, count);
+ d += count;
+ i += count;
+ }
+
+ return d;
+}
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 07/11] Add XBZRLE to ram_save_block and ram_save_live
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (5 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 06/11] Add xbzrle_encode_buffer and xbzrle_decode_buffer functions Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 08/11] Add migrate_set_cachesize command Juan Quintela
` (4 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
In the outgoing migration check to see if the page is cached and
changed, then send compressed page by using save_xbrle_page function.
In the incoming migration check to see if RAM_SAVE_FLAG_XBZRLE is set
and decompress the page (by using load_xbrle function).
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
migration.c | 24 +++++++++
migration.h | 4 ++
3 files changed, 184 insertions(+), 2 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 26f30ef..f405732 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -43,6 +43,7 @@
#include "hw/smbios.h"
#include "exec-memory.h"
#include "hw/pcspk.h"
+#include "qemu/page_cache.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
@@ -104,6 +105,7 @@ const uint32_t arch_type = QEMU_ARCH;
#define RAM_SAVE_FLAG_PAGE 0x08
#define RAM_SAVE_FLAG_EOS 0x10
#define RAM_SAVE_FLAG_CONTINUE 0x20
+#define RAM_SAVE_FLAG_XBZRLE 0x40
#ifdef __ALTIVEC__
#include <altivec.h>
@@ -171,6 +173,24 @@ static int is_dup_page(uint8_t *page)
return 1;
}
+/* struct contains XBZRLE cache and a static page
+ used by the compression */
+static struct {
+ /* buffer used for XBZRLE encoding */
+ uint8_t *encoded_buf;
+ /* buffer for storing page content */
+ uint8_t *current_buf;
+ /* buffer used for XBZRLE decoding */
+ uint8_t *decoded_buf;
+ /* Cache for XBZRLE */
+ PageCache *cache;
+} XBZRLE = {
+ .encoded_buf = NULL,
+ .current_buf = NULL,
+ .decoded_buf = NULL,
+ .cache = NULL,
+};
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -183,6 +203,53 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
}
+#define ENCODING_FLAG_XBZRLE 0x1
+
+static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
+ ram_addr_t current_addr, RAMBlock *block,
+ ram_addr_t offset, int cont)
+{
+ int encoded_len = 0, bytes_sent = -1;
+ uint8_t *prev_cached_page;
+
+ if (!cache_is_cached(XBZRLE.cache, current_addr)) {
+ cache_insert(XBZRLE.cache, current_addr,
+ g_memdup(current_data, TARGET_PAGE_SIZE));
+ return -1;
+ }
+
+ prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
+
+ /* save current buffer into memory */
+ memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
+
+ /* XBZRLE encoding (if there is no overflow) */
+ encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
+ TARGET_PAGE_SIZE, XBZRLE.encoded_buf,
+ TARGET_PAGE_SIZE);
+ if (encoded_len == 0) {
+ DPRINTF("Skipping unmodified page\n");
+ return 0;
+ } else if (encoded_len == -1) {
+ DPRINTF("Overflow\n");
+ /* update data in the cache */
+ memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
+ return -1;
+ }
+
+ /* we need to update the data in the cache, in order to get the same data */
+ memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
+
+ /* Send XBZRLE based compressed page */
+ save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
+ qemu_put_byte(f, ENCODING_FLAG_XBZRLE);
+ qemu_put_be16(f, encoded_len);
+ qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
+ bytes_sent = encoded_len + 1 + 2;
+
+ return bytes_sent;
+}
+
static RAMBlock *last_block;
static ram_addr_t last_offset;
@@ -200,6 +267,7 @@ static int ram_save_block(QEMUFile *f)
ram_addr_t offset = last_offset;
int bytes_sent = -1;
MemoryRegion *mr;
+ ram_addr_t current_addr;
if (!block)
block = QLIST_FIRST(&ram_list.blocks);
@@ -220,13 +288,24 @@ static int ram_save_block(QEMUFile *f)
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
qemu_put_byte(f, *p);
bytes_sent = 1;
- } else {
+ } else if (migrate_use_xbzrle()) {
+ current_addr = block->offset + offset;
+ bytes_sent = save_xbzrle_page(f, p, current_addr, block,
+ offset, cont);
+ p = get_cached_data(XBZRLE.cache, current_addr);
+ }
+
+ /* either we didn't send yet (we may have had XBZRLE overflow) */
+ if (bytes_sent == -1) {
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
bytes_sent = TARGET_PAGE_SIZE;
}
- break;
+ /* if page is unmodified, continue to the next */
+ if (bytes_sent != 0) {
+ break;
+ }
}
offset += TARGET_PAGE_SIZE;
@@ -304,6 +383,15 @@ static void sort_ram_list(void)
static void migration_end(void)
{
memory_global_dirty_log_stop();
+
+ if (migrate_use_xbzrle()) {
+ cache_fini(XBZRLE.cache);
+ g_free(XBZRLE.cache);
+ g_free(XBZRLE.encoded_buf);
+ g_free(XBZRLE.current_buf);
+ g_free(XBZRLE.decoded_buf);
+ XBZRLE.cache = NULL;
+ }
}
static void ram_migration_cancel(void *opaque)
@@ -323,6 +411,18 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
last_offset = 0;
sort_ram_list();
+ if (migrate_use_xbzrle()) {
+ XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
+ TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE);
+ if (!XBZRLE.cache) {
+ DPRINTF("Error creating cache\n");
+ return -1;
+ }
+ XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
+ XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
+ }
+
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
@@ -438,6 +538,47 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
return 0;
}
+static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
+{
+ int ret, rc = 0;
+ unsigned int xh_len;
+ int xh_flags;
+
+ if (!XBZRLE.decoded_buf) {
+ XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
+ }
+
+ /* extract RLE header */
+ xh_flags = qemu_get_byte(f);
+ xh_len = qemu_get_be16(f);
+
+ if (xh_flags != ENCODING_FLAG_XBZRLE) {
+ fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
+ return -1;
+ }
+
+ if (xh_len > TARGET_PAGE_SIZE) {
+ fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
+ return -1;
+ }
+ /* load data and decode */
+ qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len);
+
+ /* decode RLE */
+ ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host,
+ TARGET_PAGE_SIZE);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
+ rc = -1;
+ } else if (ret > TARGET_PAGE_SIZE) {
+ fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
+ ret, TARGET_PAGE_SIZE);
+ abort();
+ }
+
+ return rc;
+}
+
static inline void *host_from_stream_offset(QEMUFile *f,
ram_addr_t offset,
int flags)
@@ -551,6 +692,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+ } else if (flags & RAM_SAVE_FLAG_XBZRLE) {
+ if (!migrate_use_xbzrle()) {
+ return -EINVAL;
+ }
+ void *host = host_from_stream_offset(f, addr, flags);
+ if (!host) {
+ return -EINVAL;
+ }
+
+ if (load_xbzrle(f, addr, host) < 0) {
+ ret = -EINVAL;
+ goto done;
+ }
}
error = qemu_file_get_error(f);
if (error) {
diff --git a/migration.c b/migration.c
index d1a8d3a..497efc6 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,9 @@ enum {
#define MAX_THROTTLE (32 << 20) /* Migration speed throttling */
+/* Migration XBZRLE default cache size */
+#define DEFAULT_MIGRATE_CACHE_SIZE (64 * 1024 * 1024)
+
static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@@ -55,6 +58,7 @@ static MigrationState *migrate_get_current(void)
static MigrationState current_migration = {
.state = MIG_STATE_SETUP,
.bandwidth_limit = MAX_THROTTLE,
+ .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
};
return ¤t_migration;
@@ -428,6 +432,7 @@ static MigrationState *migrate_init(const MigrationParams *params)
MigrationState *s = migrate_get_current();
int64_t bandwidth_limit = s->bandwidth_limit;
bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+ int64_t xbzrle_cache_size = s->xbzrle_cache_size;
memcpy(enabled_capabilities, s->enabled_capabilities,
sizeof(enabled_capabilities));
@@ -437,6 +442,7 @@ static MigrationState *migrate_init(const MigrationParams *params)
s->params = *params;
memcpy(s->enabled_capabilities, enabled_capabilities,
sizeof(enabled_capabilities));
+ s->xbzrle_cache_size = xbzrle_cache_size;
s->bandwidth_limit = bandwidth_limit;
s->state = MIG_STATE_SETUP;
@@ -536,3 +542,21 @@ void qmp_migrate_set_downtime(double value, Error **errp)
value = MAX(0, MIN(UINT64_MAX, value));
max_downtime = (uint64_t)value;
}
+
+int migrate_use_xbzrle(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->enabled_capabilities[MIGRATION_CAPABILITY_XBZRLE];
+}
+
+int64_t migrate_xbzrle_cache_size(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->xbzrle_cache_size;
+}
diff --git a/migration.h b/migration.h
index 743c366..cdf6787 100644
--- a/migration.h
+++ b/migration.h
@@ -41,6 +41,7 @@ struct MigrationState
MigrationParams params;
int64_t total_time;
bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+ int64_t xbzrle_cache_size;
};
void process_incoming_migration(QEMUFile *f);
@@ -104,4 +105,7 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
uint8_t *dst, int dlen);
int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen);
+int migrate_use_xbzrle(void);
+int64_t migrate_xbzrle_cache_size(void);
+
#endif
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 08/11] Add migrate_set_cachesize command
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (6 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 07/11] Add XBZRLE to ram_save_block and ram_save_live Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 09/11] Add migration accounting for normal and duplicate pages Juan Quintela
` (3 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
Change XBZRLE cache size in bytes (the size should be a power of 2, it will be
rounded down to the nearest power of 2).
If XBZRLE cache size is too small there will be many cache miss.
New query-migrate-cache-size QMP command and 'info migrate-cache-size' HMP
command to query cache value.
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 10 ++++++++++
hmp-commands.hx | 22 ++++++++++++++++++++++
hmp.c | 19 +++++++++++++++++++
hmp.h | 2 ++
migration.c | 19 +++++++++++++++++++
migration.h | 2 ++
monitor.c | 7 +++++++
qapi-schema.json | 27 +++++++++++++++++++++++++++
qmp-commands.hx | 44 ++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 152 insertions(+)
diff --git a/arch_init.c b/arch_init.c
index f405732..a3346e5 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -191,6 +191,16 @@ static struct {
.cache = NULL,
};
+
+int64_t xbzrle_cache_resize(int64_t new_size)
+{
+ if (XBZRLE.cache != NULL) {
+ return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
+ TARGET_PAGE_SIZE;
+ }
+ return pow2floor(new_size);
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
diff --git a/hmp-commands.hx b/hmp-commands.hx
index f4c8495..ae98c12 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -829,6 +829,26 @@ STEXI
@item migrate_cancel
@findex migrate_cancel
Cancel the current VM migration.
+
+ETEXI
+
+ {
+ .name = "migrate_set_cachesize",
+ .args_type = "value:o",
+ .params = "value",
+ .help = "set cache size (in bytes) for XBZRLE migrations,"
+ "the cache size will be rounded down to the nearest "
+ "power of 2.\n"
+ "The cache size affects the number of cache misses."
+ "In case of a high cache miss ratio you need to increase"
+ " the cache size",
+ .mhandler.cmd = hmp_migrate_set_cachesize,
+ },
+
+STEXI
+@item migrate_set_cachesize @var{value}
+@findex migrate_set_cachesize
+Set cache size to @var{value} (in bytes) for xbzrle migrations.
ETEXI
{
@@ -1435,6 +1455,8 @@ show migration status
show migration supported capabilities
@item info migrate_capabilities
show current migration capabilities
+@item info migrate-cache-size
+show current migration XBZRLE cache size
@item info balloon
show balloon information
@item info qtree
diff --git a/hmp.c b/hmp.c
index 463b730..3a61da5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -215,6 +215,12 @@ void hmp_info_migrate_capabilities(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps);
}
+void hmp_info_migrate_cache_size(Monitor *mon)
+{
+ monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
+ qmp_query_migrate_cache_size(NULL) >> 10);
+}
+
void hmp_info_cpus(Monitor *mon)
{
CpuInfoList *cpu_list, *cpu;
@@ -783,6 +789,19 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
qmp_migrate_set_downtime(value, NULL);
}
+void hmp_migrate_set_cachesize(Monitor *mon, const QDict *qdict)
+{
+ int64_t value = qdict_get_int(qdict, "value");
+ Error *err = NULL;
+
+ qmp_migrate_set_cache_size(value, &err);
+ if (err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+}
+
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
{
int64_t value = qdict_get_int(qdict, "value");
diff --git a/hmp.h b/hmp.h
index f2a890f..0951a0e 100644
--- a/hmp.h
+++ b/hmp.h
@@ -27,6 +27,7 @@ void hmp_info_mice(Monitor *mon);
void hmp_info_migrate(Monitor *mon);
void hmp_info_migration_supported_capabilities(Monitor *mon);
void hmp_info_migrate_capabilities(Monitor *mon);
+void hmp_info_migrate_cache_size(Monitor *mon);
void hmp_info_cpus(Monitor *mon);
void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
@@ -54,6 +55,7 @@ void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_cachesize(Monitor *mon, const QDict *qdict);
void hmp_set_password(Monitor *mon, const QDict *qdict);
void hmp_expire_password(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
diff --git a/migration.c b/migration.c
index 497efc6..d007e28 100644
--- a/migration.c
+++ b/migration.c
@@ -523,6 +523,25 @@ void qmp_migrate_cancel(Error **errp)
migrate_fd_cancel(migrate_get_current());
}
+void qmp_migrate_set_cache_size(int64_t value, Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+
+ /* Check for truncation */
+ if (value != (size_t)value) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "exceeding address space");
+ return;
+ }
+
+ s->xbzrle_cache_size = xbzrle_cache_resize(value);
+}
+
+int64_t qmp_query_migrate_cache_size(Error **errp)
+{
+ return migrate_xbzrle_cache_size();
+}
+
void qmp_migrate_set_speed(int64_t value, Error **errp)
{
MigrationState *s;
diff --git a/migration.h b/migration.h
index cdf6787..337e225 100644
--- a/migration.h
+++ b/migration.h
@@ -108,4 +108,6 @@ int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen);
int migrate_use_xbzrle(void);
int64_t migrate_xbzrle_cache_size(void);
+int64_t xbzrle_cache_resize(int64_t new_size);
+
#endif
diff --git a/monitor.c b/monitor.c
index 5c5233b..3d02660 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2669,6 +2669,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_migrate_capabilities,
},
{
+ .name = "migrate-cache-size",
+ .args_type = "",
+ .params = "",
+ .help = "show current migration xbzrle cache size",
+ .mhandler.info = hmp_info_migrate_cache_size,
+ },
+ {
.name = "balloon",
.args_type = "",
.params = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index b27611b..ea33946 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1412,6 +1412,33 @@
{ 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
##
+# @migrate-set-cache-size
+#
+# Set XBZRLE cache size
+#
+# @value: cache size in bytes
+#
+# The size will be rounded down to the nearest power of 2.
+# The cache size can be modified before and during ongoing migration
+#
+# Returns: nothing on success
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
+
+##
+# @query-migrate-cache-size
+#
+# query XBZRLE cache size
+#
+# Returns: XBZRLE cache size in bytes
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-cache-size', 'returns': 'int' }
+
+##
# @ObjectPropertyInfo:
#
# @name: the name of the property
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e96a993..25a26fa 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -520,6 +520,50 @@ Example:
<- { "return": {} }
EQMP
+{
+ .name = "migrate-set-cache-size",
+ .args_type = "value:o",
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_cache_size,
+ },
+
+SQMP
+migrate-set-cache-size
+---------------------
+
+Set cache size to be used by XBZRLE migration, the cache size will be rounded
+down to the nearest power of 2
+
+Arguments:
+
+- "value": cache size in bytes (json-int)
+
+Example:
+
+-> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } }
+<- { "return": {} }
+
+EQMP
+ {
+ .name = "query-migrate-cache-size",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_migrate_cache_size,
+ },
+
+SQMP
+query-migrate-cache-size
+---------------------
+
+Show cache size to be used by XBZRLE migration
+
+returns a json-object with the following information:
+- "size" : json-int
+
+Example:
+
+-> { "execute": "query-migrate-cache-size" }
+<- { "return": { "size" : "123456" } }
+
+EQMP
{
.name = "migrate_set_speed",
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 09/11] Add migration accounting for normal and duplicate pages
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (7 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 08/11] Add migrate_set_cachesize command Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Juan Quintela
` (2 subsequent siblings)
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 38 ++++++++++++++++++++++++++++++++++++++
hmp.c | 6 ++++++
migration.c | 6 ++++++
migration.h | 5 +++++
qapi-schema.json | 11 +++++++++--
qmp-commands.hx | 26 +++++++++++++++++++++++---
6 files changed, 87 insertions(+), 5 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index a3346e5..882448e 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -201,6 +201,40 @@ int64_t xbzrle_cache_resize(int64_t new_size)
return pow2floor(new_size);
}
+/* accounting for migration statistics */
+typedef struct AccountingInfo {
+ uint64_t dup_pages;
+ uint64_t norm_pages;
+ uint64_t iterations;
+} AccountingInfo;
+
+static AccountingInfo acct_info;
+
+static void acct_clear(void)
+{
+ memset(&acct_info, 0, sizeof(acct_info));
+}
+
+uint64_t dup_mig_bytes_transferred(void)
+{
+ return acct_info.dup_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t dup_mig_pages_transferred(void)
+{
+ return acct_info.dup_pages;
+}
+
+uint64_t norm_mig_bytes_transferred(void)
+{
+ return acct_info.norm_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t norm_mig_pages_transferred(void)
+{
+ return acct_info.norm_pages;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -295,6 +329,7 @@ static int ram_save_block(QEMUFile *f)
p = memory_region_get_ram_ptr(mr) + offset;
if (is_dup_page(p)) {
+ acct_info.dup_pages++;
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
qemu_put_byte(f, *p);
bytes_sent = 1;
@@ -310,6 +345,7 @@ static int ram_save_block(QEMUFile *f)
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
bytes_sent = TARGET_PAGE_SIZE;
+ acct_info.norm_pages++;
}
/* if page is unmodified, continue to the next */
@@ -431,6 +467,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
}
XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
+ acct_clear();
}
/* Make sure all dirty bits are set */
@@ -479,6 +516,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
break;
}
bytes_transferred += bytes_sent;
+ acct_info.iterations++;
/* we want to check in the 1st loop, just in case it was the 1st time
and we had to sync the dirty bitmap.
qemu_get_clock_ns() is a bit expensive, so we only check each some
diff --git a/hmp.c b/hmp.c
index 3a61da5..f19a63b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -160,6 +160,12 @@ void hmp_info_migrate(Monitor *mon)
info->ram->total >> 10);
monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
info->ram->total_time);
+ monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
+ info->ram->duplicate);
+ monitor_printf(mon, "normal: %" PRIu64 " pagess\n",
+ info->ram->normal);
+ monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
+ info->ram->normal_bytes >> 10);
}
if (info->has_disk) {
diff --git a/migration.c b/migration.c
index d007e28..fef06b3 100644
--- a/migration.c
+++ b/migration.c
@@ -161,6 +161,9 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->ram->total = ram_bytes_total();
info->ram->total_time = qemu_get_clock_ms(rt_clock)
- s->total_time;
+ info->ram->duplicate = dup_mig_pages_transferred();
+ info->ram->normal = norm_mig_pages_transferred();
+ info->ram->normal_bytes = norm_mig_bytes_transferred();
if (blk_mig_active()) {
info->has_disk = true;
@@ -180,6 +183,9 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->ram->remaining = 0;
info->ram->total = ram_bytes_total();
info->ram->total_time = s->total_time;
+ info->ram->duplicate = dup_mig_pages_transferred();
+ info->ram->normal = norm_mig_pages_transferred();
+ info->ram->normal_bytes = norm_mig_bytes_transferred();
break;
case MIG_STATE_ERROR:
info->has_status = true;
diff --git a/migration.h b/migration.h
index 337e225..e4a7cd7 100644
--- a/migration.h
+++ b/migration.h
@@ -87,6 +87,11 @@ uint64_t ram_bytes_total(void);
extern SaveVMHandlers savevm_ram_handlers;
+uint64_t dup_mig_bytes_transferred(void);
+uint64_t dup_mig_pages_transferred(void);
+uint64_t norm_mig_bytes_transferred(void);
+uint64_t norm_mig_pages_transferred(void);
+
/**
* @migrate_add_blocker - prevent migration from proceeding
*
diff --git a/qapi-schema.json b/qapi-schema.json
index ea33946..5cbcdb4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -264,11 +264,18 @@
# migration has ended, it returns the total migration
# time. (since 1.2)
#
-# Since: 0.14.0.
+# @duplicate: number of duplicate pages (since 1.2)
+#
+# @normal : number of normal pages (since 1.2)
+#
+# @normal-bytes : number of normal bytes sent (since 1.2)
+#
+# Since: 0.14.0
##
{ 'type': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
- 'total_time': 'int' } }
+ 'total_time': 'int', 'duplicate': 'int', 'normal': 'int',
+ 'normal-bytes': 'int' } }
##
# @MigrationInfo
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 25a26fa..f7ae7e6 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2120,6 +2120,9 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
+ - "duplicate": number of duplicated pages (json-int)
+ - "normal" : number of normal pages transferred (json-int)
+ - "normal-bytes" : number of normal bytes transferred (json-int)
- "disk": only present if "status" is "active" and it is a block migration,
it is a json-object with the following disk information (in bytes):
- "transferred": amount transferred (json-int)
@@ -2136,7 +2139,18 @@ Examples:
2. Migration is done and has succeeded
-> { "execute": "query-migrate" }
-<- { "return": { "status": "completed" } }
+<- { "return": {
+ "status": "completed",
+ "ram":{
+ "transferred":123,
+ "remaining":123,
+ "total":246,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
+ }
+ }
+ }
3. Migration is done and has failed
@@ -2152,7 +2166,10 @@ Examples:
"ram":{
"transferred":123,
"remaining":123,
- "total":246
+ "total":246,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
}
}
}
@@ -2166,7 +2183,10 @@ Examples:
"ram":{
"total":1057024,
"remaining":1053304,
- "transferred":3720
+ "transferred":3720,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
},
"disk":{
"total":20971520,
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (8 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 09/11] Add migration accounting for normal and duplicate pages Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-01 19:08 ` Eric Blake
2012-08-01 18:01 ` [Qemu-devel] [PATCH 11/11] Restart optimization on stage3 update version Juan Quintela
2012-08-02 14:23 ` [Qemu-devel] [PULL 00/11] Migration next Anthony Liguori
11 siblings, 1 reply; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel; +Cc: Orit Wasserman, Benoit Hudzia, Aidan Shribman, Petter Svard
From: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 13 +++++++++++++
migration.c | 17 +++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 28 +++++++++++++++++++++++++++-
qmp-commands.hx | 36 +++++++++++++++++++++++++++++++++++-
6 files changed, 124 insertions(+), 2 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 882448e..b55f47b 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -205,7 +205,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -235,6 +239,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -259,6 +283,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -276,6 +301,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -290,6 +316,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index f19a63b..a05145a 100644
--- a/hmp.c
+++ b/hmp.c
@@ -177,6 +177,19 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->xbzrle_bytes >> 10);
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->xbzrle_pages);
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_cache_miss);
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->xbzrle_overflow);
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationCapabilityStatusList(caps);
}
diff --git a/migration.c b/migration.c
index fef06b3..15f0898 100644
--- a/migration.c
+++ b/migration.c
@@ -141,6 +141,19 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
return head;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->xbzrle_bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->xbzrle_pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->xbzrle_overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -172,8 +185,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index 5cbcdb4..f4b5a93 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -278,6 +278,27 @@
'normal-bytes': 'int' } }
##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @xbzrle-bytes: amount of bytes already transferred to the target VM
+#
+# @xbzrle-pages: amount of pages transferred to the target VM
+#
+# @xbzrle-cache-miss: @optional, number of cache miss
+#
+# @xbzrle-overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', 'xbzrle-bytes': 'int', 'xbzrle-pages': 'int',
+ 'xbzrle-cache-miss': 'int', 'xbzrle-overflow': 'int' } }
+
+##
# @MigrationInfo
#
# Information about current migration process.
@@ -295,11 +316,16 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on and
+# status is 'active' or 'completed' (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f7ae7e6..a5b35b0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2128,7 +2128,17 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
-
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
+ status is "active" or "completed"
+ - "xbzrle-pages": number of XBZRLE compressed pages, only present if
+ status is "active" or "completed"
+ - "cache-miss": number of cache misses, only present if
+ status is "active" or "completed"
+ - "overflow": number of XBZRLE overflows, only present if
+ status is "active" or "completed"
Examples:
1. Before the first migration
@@ -2196,6 +2206,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal" : 3333
+ },
+ "cache":{
+ "cache-size": 1024
+ "xbzrle-transferred":20971520,
+ "xbzrle-pages":2444343,
+ "xbzrle-cache-miss":2244,
+ "xbzrle-overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 11/11] Restart optimization on stage3 update version
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (9 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Juan Quintela
@ 2012-08-01 18:01 ` Juan Quintela
2012-08-02 14:23 ` [Qemu-devel] [PULL 00/11] Migration next Anthony Liguori
11 siblings, 0 replies; 31+ messages in thread
From: Juan Quintela @ 2012-08-01 18:01 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index b55f47b..0a9d7df 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -275,14 +275,16 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
ram_addr_t current_addr, RAMBlock *block,
- ram_addr_t offset, int cont)
+ ram_addr_t offset, int cont, bool last_stage)
{
int encoded_len = 0, bytes_sent = -1;
uint8_t *prev_cached_page;
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
- cache_insert(XBZRLE.cache, current_addr,
- g_memdup(current_data, TARGET_PAGE_SIZE));
+ if (!last_stage) {
+ cache_insert(XBZRLE.cache, current_addr,
+ g_memdup(current_data, TARGET_PAGE_SIZE));
+ }
acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -308,7 +310,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
}
/* we need to update the data in the cache, in order to get the same data */
- memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
+ if (!last_stage) {
+ memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
+ }
/* Send XBZRLE based compressed page */
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
@@ -333,7 +337,7 @@ static ram_addr_t last_offset;
* n: the amount of bytes written in other case
*/
-static int ram_save_block(QEMUFile *f)
+static int ram_save_block(QEMUFile *f, bool last_stage)
{
RAMBlock *block = last_block;
ram_addr_t offset = last_offset;
@@ -364,8 +368,10 @@ static int ram_save_block(QEMUFile *f)
} else if (migrate_use_xbzrle()) {
current_addr = block->offset + offset;
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
- offset, cont);
- p = get_cached_data(XBZRLE.cache, current_addr);
+ offset, cont, last_stage);
+ if (!last_stage) {
+ p = get_cached_data(XBZRLE.cache, current_addr);
+ }
}
/* either we didn't send yet (we may have had XBZRLE overflow) */
@@ -538,7 +544,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
- bytes_sent = ram_save_block(f);
+ bytes_sent = ram_save_block(f, false);
/* no more blocks to sent */
if (bytes_sent < 0) {
break;
@@ -600,7 +606,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
while (true) {
int bytes_sent;
- bytes_sent = ram_save_block(f);
+ bytes_sent = ram_save_block(f, true);
/* no more blocks to sent */
if (bytes_sent < 0) {
break;
--
1.7.11.2
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-01 18:01 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Juan Quintela
@ 2012-08-01 19:08 ` Eric Blake
2012-08-02 11:32 ` Orit Wasserman
0 siblings, 1 reply; 31+ messages in thread
From: Eric Blake @ 2012-08-01 19:08 UTC (permalink / raw)
To: Juan Quintela
Cc: Orit Wasserman, Benoit Hudzia, qemu-devel, Aidan Shribman,
Petter Svard
[-- Attachment #1: Type: text/plain, Size: 3839 bytes --]
On 08/01/2012 12:01 PM, Juan Quintela wrote:
> From: Orit Wasserman <owasserm@redhat.com>
>
> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> Signed-off-by: Petter Svard <petters@cs.umu.se>
> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
> arch_init.c | 28 ++++++++++++++++++++++++++++
> hmp.c | 13 +++++++++++++
> migration.c | 17 +++++++++++++++++
> migration.h | 4 ++++
> qapi-schema.json | 28 +++++++++++++++++++++++++++-
> qmp-commands.hx | 36 +++++++++++++++++++++++++++++++++++-
> 6 files changed, 124 insertions(+), 2 deletions(-)
>
> ##
> +# @XBZRLECacheStats
> +#
> +# Detailed XBZRLE migration cache statistics
> +#
> +# @cache-size: XBZRLE cache size
> +#
> +# @xbzrle-bytes: amount of bytes already transferred to the target VM
> +#
> +# @xbzrle-pages: amount of pages transferred to the target VM
> +#
> +# @xbzrle-cache-miss: @optional, number of cache miss
> +#
> +# @xbzrle-overflow: number of overflows
> +#
> +# Since: 1.2
> +##
> +{ 'type': 'XBZRLECacheStats',
> + 'data': {'cache-size': 'int', 'xbzrle-bytes': 'int', 'xbzrle-pages': 'int',
> + 'xbzrle-cache-miss': 'int', 'xbzrle-overflow': 'int' } }
Given that this struct already has xbzrle in the name, do all the fields
need to repeat that information?
> +++ b/qmp-commands.hx
> @@ -2128,7 +2128,17 @@ The main json-object contains the following:
> - "transferred": amount transferred (json-int)
> - "remaining": amount remaining (json-int)
> - "total": total (json-int)
> -
> +- "xbzrle-cache": only present if XBZRLE is active.
> + It is a json-object with the following XBZRLE information:
> + - "cache-size": XBZRLE cache size
> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
> + status is "active" or "completed"
> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
> + status is "active" or "completed"
> + - "cache-miss": number of cache misses, only present if
s/cache-miss/xbzrle-cache-miss/ (unless you heed my earlier complaint,
then s/xbzrle-bytes/bytes/ instead)
> + status is "active" or "completed"
> + - "overflow": number of XBZRLE overflows, only present if
s/overflow/xbzrle-overflow/
> + status is "active" or "completed"
Given that the overall 'xbzrle-cache' struct is already documented as
present when XBZRLE is active, do you need to also document that the
subfields are present when active or completed?
> Examples:
>
> 1. Before the first migration
> @@ -2196,6 +2206,30 @@ Examples:
> }
> }
>
> +6. Migration is being performed and XBZRLE is active:
> +
> +-> { "execute": "query-migrate" }
> +<- {
> + "return":{
> + "status":"active",
> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
> + "ram":{
> + "total":1057024,
> + "remaining":1053304,
> + "transferred":3720,
> + "duplicate": 10,
> + "normal" : 3333
Inconsistent spacing around these ':'.
> + },
> + "cache":{
s/cache/xbzrle-cache/
> + "cache-size": 1024
s/ 1024/1024,/
> + "xbzrle-transferred":20971520,
> + "xbzrle-pages":2444343,
> + "xbzrle-cache-miss":2244,
> + "xbzrle-overflow":34434
and if you take my earlier comments, these lines would change too.
--
Eric Blake eblake@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 620 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-01 19:08 ` Eric Blake
@ 2012-08-02 11:32 ` Orit Wasserman
0 siblings, 0 replies; 31+ messages in thread
From: Orit Wasserman @ 2012-08-02 11:32 UTC (permalink / raw)
To: qemu-devel
On 08/01/2012 10:08 PM, Eric Blake wrote:
> On 08/01/2012 12:01 PM, Juan Quintela wrote:
>> From: Orit Wasserman <owasserm@redhat.com>
>>
>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
>> Signed-off-by: Petter Svard <petters@cs.umu.se>
>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>> arch_init.c | 28 ++++++++++++++++++++++++++++
>> hmp.c | 13 +++++++++++++
>> migration.c | 17 +++++++++++++++++
>> migration.h | 4 ++++
>> qapi-schema.json | 28 +++++++++++++++++++++++++++-
>> qmp-commands.hx | 36 +++++++++++++++++++++++++++++++++++-
>> 6 files changed, 124 insertions(+), 2 deletions(-)
>>
>
>> ##
>> +# @XBZRLECacheStats
>> +#
>> +# Detailed XBZRLE migration cache statistics
>> +#
>> +# @cache-size: XBZRLE cache size
>> +#
>> +# @xbzrle-bytes: amount of bytes already transferred to the target VM
>> +#
>> +# @xbzrle-pages: amount of pages transferred to the target VM
>> +#
>> +# @xbzrle-cache-miss: @optional, number of cache miss
>> +#
>> +# @xbzrle-overflow: number of overflows
>> +#
>> +# Since: 1.2
>> +##
>> +{ 'type': 'XBZRLECacheStats',
>> + 'data': {'cache-size': 'int', 'xbzrle-bytes': 'int', 'xbzrle-pages': 'int',
>> + 'xbzrle-cache-miss': 'int', 'xbzrle-overflow': 'int' } }
>
> Given that this struct already has xbzrle in the name, do all the fields
> need to repeat that information?
I will remove it.
>
>> +++ b/qmp-commands.hx
>> @@ -2128,7 +2128,17 @@ The main json-object contains the following:
>> - "transferred": amount transferred (json-int)
>> - "remaining": amount remaining (json-int)
>> - "total": total (json-int)
>> -
>> +- "xbzrle-cache": only present if XBZRLE is active.
>> + It is a json-object with the following XBZRLE information:
>> + - "cache-size": XBZRLE cache size
>> + - "xbzrle-bytes": total XBZRLE bytes transferred, only present if
>> + status is "active" or "completed"
>> + - "xbzrle-pages": number of XBZRLE compressed pages, only present if
>> + status is "active" or "completed"
>> + - "cache-miss": number of cache misses, only present if
>
> s/cache-miss/xbzrle-cache-miss/ (unless you heed my earlier complaint,
> then s/xbzrle-bytes/bytes/ instead)
>
>> + status is "active" or "completed"
>> + - "overflow": number of XBZRLE overflows, only present if
>
> s/overflow/xbzrle-overflow/
>
>> + status is "active" or "completed"
>
> Given that the overall 'xbzrle-cache' struct is already documented as
> present when XBZRLE is active, do you need to also document that the
> subfields are present when active or completed?
I will remove the comment
Orit
>
>> Examples:
>>
>> 1. Before the first migration
>> @@ -2196,6 +2206,30 @@ Examples:
>> }
>> }
>>
>> +6. Migration is being performed and XBZRLE is active:
>> +
>> +-> { "execute": "query-migrate" }
>> +<- {
>> + "return":{
>> + "status":"active",
>> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
>> + "ram":{
>> + "total":1057024,
>> + "remaining":1053304,
>> + "transferred":3720,
>> + "duplicate": 10,
>> + "normal" : 3333
>
> Inconsistent spacing around these ':'.
>
>> + },
>> + "cache":{
>
> s/cache/xbzrle-cache/
>
>> + "cache-size": 1024
>
> s/ 1024/1024,/
>
>> + "xbzrle-transferred":20971520,
>> + "xbzrle-pages":2444343,
>> + "xbzrle-cache-miss":2244,
>> + "xbzrle-overflow":34434
>
> and if you take my earlier comments, these lines would change too.
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-02 12:44 [Qemu-devel] [PATCH 00/11] Migration next v9 Orit Wasserman
@ 2012-08-02 12:44 ` Orit Wasserman
2012-08-02 14:01 ` Eric Blake
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-08-02 12:44 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, aliguori, quintela, Petter Svard, stefanha, mdroth,
Benoit Hudzia, lcapitulino, blauwirbel, Orit Wasserman,
chegu_vinod, avi, Aidan Shribman, pbonzini, eblake
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 13 +++++++++++++
migration.c | 17 +++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 28 +++++++++++++++++++++++++++-
qmp-commands.hx | 32 +++++++++++++++++++++++++++++++-
6 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 7f12317..9833d54 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index f19a63b..9b77c44 100644
--- a/hmp.c
+++ b/hmp.c
@@ -177,6 +177,19 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->bytes >> 10);
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->pages);
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->cache_miss);
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->overflow);
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationCapabilityStatusList(caps);
}
diff --git a/migration.c b/migration.c
index fef06b3..4874a2c 100644
--- a/migration.c
+++ b/migration.c
@@ -141,6 +141,19 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
return head;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -172,8 +185,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index e0832ea..1a7f0c9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -278,6 +278,27 @@
'normal-bytes': 'int' } }
##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @bytes: amount of bytes already transferred to the target VM
+#
+# @pages: amount of pages transferred to the target VM
+#
+# @cache-miss: number of cache miss
+#
+# @overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
+ 'cache-miss': 'int', 'overflow': 'int' } }
+
+##
# @MigrationInfo
#
# Information about current migration process.
@@ -295,11 +316,16 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on and
+# status is 'active' or 'completed' (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index f7ae7e6..cb6cac8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2128,7 +2128,13 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
-
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "bytes": total XBZRLE bytes transferred
+ - "pages": number of XBZRLE compressed pages
+ - "cache-miss": number of cache misses
+ - "overflow": number of XBZRLE overflows
Examples:
1. Before the first migration
@@ -2196,6 +2202,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate": 10,
+ "normal": 3333
+ },
+ "xbzrle-cache":{
+ "cache-size": 1024,
+ "transferred":20971520,
+ "pages":2444343,
+ "cache-miss":2244,
+ "overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-02 12:44 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
@ 2012-08-02 14:01 ` Eric Blake
2012-08-02 17:01 ` Orit Wasserman
0 siblings, 1 reply; 31+ messages in thread
From: Eric Blake @ 2012-08-02 14:01 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel, mdroth,
blauwirbel, Petter Svard, Benoit Hudzia, avi, Aidan Shribman,
pbonzini, lcapitulino, chegu_vinod
[-- Attachment #1: Type: text/plain, Size: 1196 bytes --]
On 08/02/2012 06:44 AM, Orit Wasserman wrote:
> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> Signed-off-by: Petter Svard <petters@cs.umu.se>
> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
>
> +6. Migration is being performed and XBZRLE is active:
> +
> +-> { "execute": "query-migrate" }
> +<- {
> + "return":{
> + "status":"active",
> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
> + "ram":{
> + "total":1057024,
> + "remaining":1053304,
> + "transferred":3720,
> + "duplicate": 10,
> + "normal": 3333
> + },
> + "xbzrle-cache":{
> + "cache-size": 1024,
Is this value in bytes? It should be. Which means that this example is
bogus - 1024 is smaller than one page, but your caching code rounded to
page boundaries. Sounds like you forgot a scaling factor somewhere.
Also, s/: /:/
--
Eric Blake eblake@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 620 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PULL 00/11] Migration next
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
` (10 preceding siblings ...)
2012-08-01 18:01 ` [Qemu-devel] [PATCH 11/11] Restart optimization on stage3 update version Juan Quintela
@ 2012-08-02 14:23 ` Anthony Liguori
11 siblings, 0 replies; 31+ messages in thread
From: Anthony Liguori @ 2012-08-02 14:23 UTC (permalink / raw)
To: Juan Quintela; +Cc: qemu-devel
On 08/01/2012 01:01 PM, Juan Quintela wrote:
> Hi
>
> Here is the xbzrle pull request. All comments about QMP names addressed.
>
> Please, pull
>
> The following changes since commit 02d2bd5d57812154cfb978bc2098cf49d551583d:
>
> Replace 'struct siginfo' with 'siginfo_t'. (2012-08-01 08:54:07 -0500)
>
> are available in the git repository at:
>
> http://repo.or.cz/r/qemu/quintela.git migration-next-20120801
>
> for you to fetch changes up to 7bff472b8fba64b7417c243d2132422afc0c2137:
>
> Restart optimization on stage3 update version (2012-08-01 19:56:57 +0200)
This pull request is premature as there's a v9 that went out after your pull
request (and got review feedback).
Please wait until the patches actually collect some Reviewed-by's on the list
before submitting a pull request.
Regards,
Anthony Liguori
>
>
>
> Juan Quintela (1):
> Restart optimization on stage3 update version
>
> Orit Wasserman (10):
> Add migration capabilities
> Add migrate-set-capabilities and query-migrate-capabilities
> Add XBZRLE documentation
> Add cache handling functions
> Add uleb encoding/decoding functions
> Add xbzrle_encode_buffer and xbzrle_decode_buffer functions
> Add XBZRLE to ram_save_block and ram_save_live
> Add migrate_set_cachesize command
> Add migration accounting for normal and duplicate pages
> Add XBZRLE statistics
>
> Makefile.objs | 1 +
> arch_init.c | 246 +++++++++++++++++++++++++++++++++++++++++++++-
> cutils.c | 42 ++++++++
> docs/xbzrle.txt | 136 +++++++++++++++++++++++++
> hmp-commands.hx | 40 ++++++++
> hmp.c | 124 +++++++++++++++++++++++
> hmp.h | 5 +
> include/qemu/page_cache.h | 79 +++++++++++++++
> migration.c | 124 +++++++++++++++++++++++
> migration.h | 21 ++++
> monitor.c | 21 ++++
> page_cache.c | 218 ++++++++++++++++++++++++++++++++++++++++
> qapi-schema.json | 137 +++++++++++++++++++++++++-
> qemu-common.h | 21 ++++
> qmp-commands.hx | 180 ++++++++++++++++++++++++++++++++-
> savevm.c | 159 ++++++++++++++++++++++++++++++
> 16 files changed, 1542 insertions(+), 12 deletions(-)
> create mode 100644 docs/xbzrle.txt
> create mode 100644 include/qemu/page_cache.h
> create mode 100644 page_cache.c
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-02 14:01 ` Eric Blake
@ 2012-08-02 17:01 ` Orit Wasserman
0 siblings, 0 replies; 31+ messages in thread
From: Orit Wasserman @ 2012-08-02 17:01 UTC (permalink / raw)
To: qemu-devel
On 08/02/2012 05:01 PM, Eric Blake wrote:
> On 08/02/2012 06:44 AM, Orit Wasserman wrote:
>> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
>> Signed-off-by: Petter Svard <petters@cs.umu.se>
>> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
>> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>
>
>>
>> +6. Migration is being performed and XBZRLE is active:
>> +
>> +-> { "execute": "query-migrate" }
>> +<- {
>> + "return":{
>> + "status":"active",
>> + "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
>> + "ram":{
>> + "total":1057024,
>> + "remaining":1053304,
>> + "transferred":3720,
>> + "duplicate": 10,
>> + "normal": 3333
>> + },
>> + "xbzrle-cache":{
>> + "cache-size": 1024,
>
> Is this value in bytes? It should be. Which means that this example is
> bogus - 1024 is smaller than one page, but your caching code rounded to
> page boundaries. Sounds like you forgot a scaling factor somewhere.
> Also, s/: /:/
>
will be fixed,
Thanks,
Orit
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-05 9:13 [Qemu-devel] [PATCH 00/11] Migration next v10 Orit Wasserman
@ 2012-08-05 9:13 ` Orit Wasserman
2012-08-06 15:55 ` Eric Blake
0 siblings, 1 reply; 31+ messages in thread
From: Orit Wasserman @ 2012-08-05 9:13 UTC (permalink / raw)
To: qemu-devel
Cc: peter.maydell, aliguori, quintela, Petter Svard, stefanha, mdroth,
Benoit Hudzia, lcapitulino, blauwirbel, Orit Wasserman,
chegu_vinod, avi, Aidan Shribman, pbonzini, eblake
Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
Signed-off-by: Orit Wasserman <owasserm@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
arch_init.c | 28 ++++++++++++++++++++++++++++
hmp.c | 13 +++++++++++++
migration.c | 17 +++++++++++++++++
migration.h | 4 ++++
qapi-schema.json | 28 +++++++++++++++++++++++++++-
qmp-commands.hx | 32 +++++++++++++++++++++++++++++++-
6 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index 7f12317..9833d54 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
typedef struct AccountingInfo {
uint64_t dup_pages;
uint64_t norm_pages;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
uint64_t iterations;
+ uint64_t xbzrle_overflows;
} AccountingInfo;
static AccountingInfo acct_info;
@@ -233,6 +237,26 @@ uint64_t norm_mig_pages_transferred(void)
return acct_info.norm_pages;
}
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -257,6 +281,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
cache_insert(XBZRLE.cache, current_addr,
g_memdup(current_data, TARGET_PAGE_SIZE));
+ acct_info.xbzrle_cache_miss++;
return -1;
}
@@ -274,6 +299,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
return 0;
} else if (encoded_len == -1) {
DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
/* update data in the cache */
memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
return -1;
@@ -288,6 +314,8 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
qemu_put_be16(f, encoded_len);
qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
return bytes_sent;
}
diff --git a/hmp.c b/hmp.c
index 31c7f3f..6103e5a 100644
--- a/hmp.c
+++ b/hmp.c
@@ -177,6 +177,19 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->bytes >> 10);
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->pages);
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->cache_miss);
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->overflow);
+ }
+
qapi_free_MigrationInfo(info);
qapi_free_MigrationCapabilityStatusList(caps);
}
diff --git a/migration.c b/migration.c
index 9e6b791..1a94931 100644
--- a/migration.c
+++ b/migration.c
@@ -141,6 +141,19 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
return head;
}
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -172,8 +185,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
diff --git a/migration.h b/migration.h
index e4a7cd7..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -91,6 +91,10 @@ uint64_t dup_mig_bytes_transferred(void);
uint64_t dup_mig_pages_transferred(void);
uint64_t norm_mig_bytes_transferred(void);
uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
/**
* @migrate_add_blocker - prevent migration from proceeding
diff --git a/qapi-schema.json b/qapi-schema.json
index edc782a..ba6036d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -278,6 +278,27 @@
'normal-bytes': 'int' } }
##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @bytes: amount of bytes already transferred to the target VM
+#
+# @pages: amount of pages transferred to the target VM
+#
+# @cache-miss: number of cache miss
+#
+# @overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
+ 'cache-miss': 'int', 'overflow': 'int' } }
+
+##
# @MigrationInfo
#
# Information about current migration process.
@@ -295,11 +316,16 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on and
+# status is 'active' or 'completed' (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats'} }
##
# @query-migrate
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d7ec281..9430d09 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2128,7 +2128,13 @@ The main json-object contains the following:
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
-
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "bytes": total XBZRLE bytes transferred
+ - "pages": number of XBZRLE compressed pages
+ - "cache-miss": number of cache misses
+ - "overflow": number of XBZRLE overflows
Examples:
1. Before the first migration
@@ -2196,6 +2202,30 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "duplicate":10,
+ "normal":3333
+ },
+ "xbzrle-cache":{
+ "cache-size":67108864,
+ "transferred":20971520,
+ "pages":2444343,
+ "cache-miss":2244,
+ "overflow":34434
+ }
+ }
+ }
+
EQMP
{
--
1.7.7.6
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics
2012-08-05 9:13 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
@ 2012-08-06 15:55 ` Eric Blake
0 siblings, 0 replies; 31+ messages in thread
From: Eric Blake @ 2012-08-06 15:55 UTC (permalink / raw)
To: Orit Wasserman
Cc: peter.maydell, aliguori, quintela, stefanha, qemu-devel, mdroth,
blauwirbel, Petter Svard, Benoit Hudzia, avi, Aidan Shribman,
pbonzini, lcapitulino, chegu_vinod
[-- Attachment #1: Type: text/plain, Size: 1333 bytes --]
On 08/05/2012 03:13 AM, Orit Wasserman wrote:
> Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
> Signed-off-by: Petter Svard <petters@cs.umu.se>
> Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>
> Signed-off-by: Orit Wasserman <owasserm@redhat.com>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
> arch_init.c | 28 ++++++++++++++++++++++++++++
> hmp.c | 13 +++++++++++++
> migration.c | 17 +++++++++++++++++
> migration.h | 4 ++++
> qapi-schema.json | 28 +++++++++++++++++++++++++++-
> qmp-commands.hx | 32 +++++++++++++++++++++++++++++++-
> 6 files changed, 120 insertions(+), 2 deletions(-)
>
> diff --git a/arch_init.c b/arch_init.c
> index 7f12317..9833d54 100644
> --- a/arch_init.c
> +++ b/arch_init.c
> @@ -203,7 +203,11 @@ int64_t xbzrle_cache_resize(int64_t new_size)
> typedef struct AccountingInfo {
> uint64_t dup_pages;
> uint64_t norm_pages;
> + uint64_t xbzrle_bytes;
> + uint64_t xbzrle_pages;
> + uint64_t xbzrle_cache_miss;
> uint64_t iterations;
> + uint64_t xbzrle_overflows;
Any reason you stagger where these stats are stored, rather than piling
them all at the end?
--
Eric Blake eblake@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 620 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2012-08-06 15:56 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-01 18:01 [Qemu-devel] [PULL 00/11] Migration next Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 01/11] Add migration capabilities Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 02/11] Add migrate-set-capabilities and query-migrate-capabilities Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 03/11] Add XBZRLE documentation Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 04/11] Add cache handling functions Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 05/11] Add uleb encoding/decoding functions Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 06/11] Add xbzrle_encode_buffer and xbzrle_decode_buffer functions Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 07/11] Add XBZRLE to ram_save_block and ram_save_live Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 08/11] Add migrate_set_cachesize command Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 09/11] Add migration accounting for normal and duplicate pages Juan Quintela
2012-08-01 18:01 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Juan Quintela
2012-08-01 19:08 ` Eric Blake
2012-08-02 11:32 ` Orit Wasserman
2012-08-01 18:01 ` [Qemu-devel] [PATCH 11/11] Restart optimization on stage3 update version Juan Quintela
2012-08-02 14:23 ` [Qemu-devel] [PULL 00/11] Migration next Anthony Liguori
-- strict thread matches above, loose matches on Subject: below --
2012-08-05 9:13 [Qemu-devel] [PATCH 00/11] Migration next v10 Orit Wasserman
2012-08-05 9:13 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
2012-08-06 15:55 ` Eric Blake
2012-08-02 12:44 [Qemu-devel] [PATCH 00/11] Migration next v9 Orit Wasserman
2012-08-02 12:44 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
2012-08-02 14:01 ` Eric Blake
2012-08-02 17:01 ` Orit Wasserman
2012-07-31 18:54 [Qemu-devel] [PATCH 00/11] Migration next v8 Orit Wasserman
2012-07-31 18:54 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
2012-07-29 9:42 [Qemu-devel] [PATCH 00/11] Migration next v7 Orit Wasserman
2012-07-29 9:43 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
2012-07-30 19:37 ` Luiz Capitulino
2012-07-31 8:31 ` Orit Wasserman
2012-07-31 13:16 ` Luiz Capitulino
2012-07-31 14:13 ` Orit Wasserman
2012-07-31 15:54 ` Luiz Capitulino
2012-07-25 14:50 [Qemu-devel] [PATCH 00/11] Migration next v6 Orit Wasserman
2012-07-25 14:50 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Orit Wasserman
2012-07-26 22:48 ` Eric Blake
2012-07-29 7:10 ` Orit Wasserman
2012-07-24 18:19 [Qemu-devel] [PATCH 00/11] Migration next v5 Juan Quintela
2012-07-24 18:19 ` [Qemu-devel] [PATCH 10/11] Add XBZRLE statistics Juan Quintela
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).