* [Qemu-devel] [RFC 0/3] qtest: base64 r/w and faster memset
@ 2015-02-25 16:34 John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 1/3] qtest: allow arbitrarily long sends John Snow
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: John Snow @ 2015-02-25 16:34 UTC (permalink / raw)
To: qemu-devel; +Cc: marc.mari.barcelo, pbonzini, John Snow, afaerber, stefanha
Adds new qtest protocol commands for base64 reads and writes,
as well as a proper command for memset instead of faking it
via write.
RFC: Should base64 be the default, and hex nibbles be the opt-in?
Base64 hampers the debugability of smaller reads/writes for which
base64 won't provide much line speed improvement.
On the other hand, the more efficient encoding could benefit
any tests that send more than a couple of bytes of data at a time.
John Snow (3):
qtest: allow arbitrarily long sends
qtest: Add base64 encoded read/write
qtest: add memset to qtest protocol
qtest.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
tests/libqtest.c | 39 ++++++++++++++++++-----
tests/libqtest.h | 49 +++++++++++++++++++++++++++++
3 files changed, 173 insertions(+), 9 deletions(-)
--
1.9.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [RFC 1/3] qtest: allow arbitrarily long sends
2015-02-25 16:34 [Qemu-devel] [RFC 0/3] qtest: base64 r/w and faster memset John Snow
@ 2015-02-25 16:34 ` John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 2/3] qtest: Add base64 encoded read/write John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 3/3] qtest: add memset to qtest protocol John Snow
2 siblings, 0 replies; 4+ messages in thread
From: John Snow @ 2015-02-25 16:34 UTC (permalink / raw)
To: qemu-devel; +Cc: marc.mari.barcelo, pbonzini, John Snow, afaerber, stefanha
qtest currently has a static buffer of size 1024 that if we
overflow, ignores the additional data silently which leads
to hangs or stream failures.
Use glib's string facilities to allow arbitrarily long data.
Signed-off-by: John Snow <jsnow@redhat.com>
---
qtest.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/qtest.c b/qtest.c
index 2bca04e..242dcc0 100644
--- a/qtest.c
+++ b/qtest.c
@@ -186,11 +186,12 @@ static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
const char *fmt, ...)
{
va_list ap;
- char buffer[1024];
size_t len;
+ gchar *buffer;
va_start(ap, fmt);
- len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ buffer = g_strdup_vprintf(fmt, ap);
+ len = strlen(buffer);
va_end(ap);
qemu_chr_fe_write_all(chr, (uint8_t *)buffer, len);
--
1.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [RFC 2/3] qtest: Add base64 encoded read/write
2015-02-25 16:34 [Qemu-devel] [RFC 0/3] qtest: base64 r/w and faster memset John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 1/3] qtest: allow arbitrarily long sends John Snow
@ 2015-02-25 16:34 ` John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 3/3] qtest: add memset to qtest protocol John Snow
2 siblings, 0 replies; 4+ messages in thread
From: John Snow @ 2015-02-25 16:34 UTC (permalink / raw)
To: qemu-devel; +Cc: marc.mari.barcelo, pbonzini, John Snow, afaerber, stefanha
For larger pieces of data that won't need to be debugged and
viewing the hex nibbles is unlikely to be useful, we can encode
data using base64 instead of encoding each byte as %02x, which
leads to some space savings and faster reads/writes.
For now, the default is left as hex nibbles in memwrite() and memread().
This RFC asks if it's worth setting the default to base64 encoding,
and adding separate calls to allow callers to specify which encoding
they would like.
For the purposes of making qtest io easier to read and debug, some
callers may want to specify using the old encoding format for small
patches of data where the savings from base64 wouldn't be that profound.
Signed-off-by: John Snow <jsnow@redhat.com>
---
qtest.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/libqtest.c | 31 +++++++++++++++++++++++++
tests/libqtest.h | 49 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+)
diff --git a/qtest.c b/qtest.c
index 242dcc0..80c2864 100644
--- a/qtest.c
+++ b/qtest.c
@@ -119,12 +119,21 @@ static bool qtest_opened;
* > write ADDR SIZE DATA
* < OK
*
+ * > b64read ADDR SIZE
+ * < OK B64_DATA
+ *
+ * > b64write ADDR SIZE B64_DATA
+ * < OK
+ *
* ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
*
* DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
* than the expected size, the value will be zero filled at the end of the data
* sequence.
*
+ * B64_DATA is an arbitrarily long base64 encoded string.
+ * If the sizes do not match, the data will be truncated.
+ *
* IRQ management:
*
* > irq_intercept_in QOM-PATH
@@ -182,6 +191,21 @@ static void qtest_send_prefix(CharDriverState *chr)
(long) tv.tv_sec, (long) tv.tv_usec);
}
+static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!qtest_log_fp || !qtest_opened) {
+ return;
+ }
+
+ qtest_send_prefix(NULL);
+
+ va_start(ap, fmt);
+ vfprintf(qtest_log_fp, fmt, ap);
+ va_end(ap);
+}
+
static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
const char *fmt, ...)
{
@@ -396,6 +420,23 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send(chr, "\n");
g_free(data);
+ } else if (strcmp(words[0], "b64read") == 0) {
+ uint64_t addr, len;
+ uint8_t *data;
+ gchar *b64_data;
+
+ g_assert(words[1] && words[2]);
+ addr = strtoull(words[1], NULL, 0);
+ len = strtoull(words[2], NULL, 0);
+
+ data = g_malloc(len);
+ cpu_physical_memory_read(addr, data, len);
+ b64_data = g_base64_encode(data, len);
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK %s\n", b64_data);
+
+ g_free(data);
+ g_free(b64_data);
} else if (strcmp(words[0], "write") == 0) {
uint64_t addr, len, i;
uint8_t *data;
@@ -425,6 +466,34 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "b64write") == 0) {
+ uint64_t addr, len;
+ uint8_t *data;
+ size_t data_len;
+ gsize out_len;
+
+ g_assert(words[1] && words[2] && words[3]);
+ addr = strtoull(words[1], NULL, 0);
+ len = strtoull(words[2], NULL, 0);
+
+ data_len = strlen(words[3]);
+ if (data_len < 3) {
+ qtest_send(chr, "ERR invalid argument size\n");
+ return;
+ }
+
+ data = g_base64_decode_inplace(words[3], &out_len);
+ if (out_len != len) {
+ qtest_log_send("b64write: data length mismatch (told %zu, "
+ "found %zu)\n",
+ len, out_len);
+ out_len = MIN(out_len, len);
+ }
+
+ cpu_physical_memory_write(addr, data, out_len);
+
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
} else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
int64_t ns;
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 9a92aa7..396558a 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -652,6 +652,37 @@ void qtest_add_func(const char *str, void (*fn))
g_free(path);
}
+void qtest_bufwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+ gchar *bdata;
+
+ bdata = g_base64_encode(data, size);
+ qtest_sendf(s, "b64write 0x%" PRIx64 " 0x%zx ", addr, size);
+ socket_send(s->fd, bdata, strlen(bdata));
+ socket_send(s->fd, "\n", 1);
+ qtest_rsp(s, 0);
+ g_free(bdata);
+}
+
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+ gchar **args;
+ size_t len;
+
+ qtest_sendf(s, "b64read 0x%" PRIx64 " 0x%zx\n", addr, size);
+ args = qtest_rsp(s, 2);
+
+ g_base64_decode_inplace(args[1], &len);
+ if (size != len) {
+ fprintf(stderr, "bufread: asked for %zu bytes but decoded %zu\n",
+ size, len);
+ len = MIN(len, size);
+ }
+
+ memcpy(data, args[1], len);
+ g_strfreev(args);
+}
+
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
{
const uint8_t *ptr = data;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index e7413d5..d197b06 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -273,6 +273,17 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
/**
+ * qtest_bufread:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer and receive using a base64 encoding.
+ */
+void qtest_bufread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
* qtest_memwrite:
* @s: #QTestState instance to operate on.
* @addr: Guest address to write to.
@@ -284,6 +295,18 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
/**
+ * qtest_memwrite:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory and transmit using a base64 encoding.
+ */
+void qtest_bufwrite(QTestState *s, uint64_t addr,
+ const void *data, size_t size);
+
+/**
* qtest_memset:
* @s: #QTestState instance to operate on.
* @addr: Guest address to write to.
@@ -620,6 +643,19 @@ static inline void memread(uint64_t addr, void *data, size_t size)
}
/**
+ * bufread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer, receive using a base64 encoding.
+ */
+static inline void bufread(uint64_t addr, void *data, size_t size)
+{
+ qtest_bufread(global_qtest, addr, data, size);
+}
+
+/**
* memwrite:
* @addr: Guest address to write to.
* @data: Pointer to the bytes that will be written to guest memory.
@@ -633,6 +669,19 @@ static inline void memwrite(uint64_t addr, const void *data, size_t size)
}
/**
+ * bufwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory, transmit using a base64 encoding.
+ */
+static inline void bufwrite(uint64_t addr, const void *data, size_t size)
+{
+ qtest_bufwrite(global_qtest, addr, data, size);
+}
+
+/**
* qmemset:
* @addr: Guest address to write to.
* @patt: Byte pattern to fill the guest memory region with.
--
1.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [RFC 3/3] qtest: add memset to qtest protocol
2015-02-25 16:34 [Qemu-devel] [RFC 0/3] qtest: base64 r/w and faster memset John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 1/3] qtest: allow arbitrarily long sends John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 2/3] qtest: Add base64 encoded read/write John Snow
@ 2015-02-25 16:34 ` John Snow
2 siblings, 0 replies; 4+ messages in thread
From: John Snow @ 2015-02-25 16:34 UTC (permalink / raw)
To: qemu-devel; +Cc: marc.mari.barcelo, pbonzini, John Snow, afaerber, stefanha
Previously, memset was just a frontend to write() and only
stupidly sent the pattern many times across the wire.
Let's not discuss who stupidly wrote it like that in the first place.
Signed-off-by: John Snow <jsnow@redhat.com>
---
qtest.c | 20 ++++++++++++++++++++
tests/libqtest.c | 8 +-------
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/qtest.c b/qtest.c
index 80c2864..576fb60 100644
--- a/qtest.c
+++ b/qtest.c
@@ -125,6 +125,9 @@ static bool qtest_opened;
* > b64write ADDR SIZE B64_DATA
* < OK
*
+ * > memset ADDR SIZE VALUE
+ * < OK
+ *
* ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
*
* DATA is an arbitrarily long hex number prefixed with '0x'. If it's smaller
@@ -466,6 +469,23 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "memset") == 0) {
+ uint64_t addr, len;
+ uint8_t *data;
+ uint8_t pattern;
+
+ g_assert(words[1] && words[2] && words[3]);
+ addr = strtoull(words[1], NULL, 0);
+ len = strtoull(words[2], NULL, 0);
+ pattern = strtoull(words[3], NULL, 0);
+
+ data = g_malloc(len);
+ memset(data, pattern, len);
+ cpu_physical_memory_write(addr, data, len);
+ g_free(data);
+
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "b64write") == 0) {
uint64_t addr, len;
uint8_t *data;
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 396558a..efb0837 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -698,13 +698,7 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
{
- size_t i;
-
- qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x", addr, size);
- for (i = 0; i < size; i++) {
- qtest_sendf(s, "%02x", pattern);
- }
- qtest_sendf(s, "\n");
+ qtest_sendf(s, "memset 0x%" PRIx64 " 0x%zx 0x%02x\n", addr, size, pattern);
qtest_rsp(s, 0);
}
--
1.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-02-25 17:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-25 16:34 [Qemu-devel] [RFC 0/3] qtest: base64 r/w and faster memset John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 1/3] qtest: allow arbitrarily long sends John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 2/3] qtest: Add base64 encoded read/write John Snow
2015-02-25 16:34 ` [Qemu-devel] [RFC 3/3] qtest: add memset to qtest protocol John Snow
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).