summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorØyvind Harboe <oyvind.harboe@zylin.com>2010-03-16 14:45:07 +0100
committerØyvind Harboe <oyvind.harboe@zylin.com>2010-03-17 07:40:00 +0100
commit051e2c99ab8111f6bffdb412b40ceef333530ae6 (patch)
tree6fd42f5ea240924cc1f8f7939186e6435db145c9 /src/server
parent7e447043cd7967bd9b8976d829d5cb79bf359d3c (diff)
downloadopenocd+libswd-051e2c99ab8111f6bffdb412b40ceef333530ae6.tar.gz
openocd+libswd-051e2c99ab8111f6bffdb412b40ceef333530ae6.tar.bz2
openocd+libswd-051e2c99ab8111f6bffdb412b40ceef333530ae6.tar.xz
openocd+libswd-051e2c99ab8111f6bffdb412b40ceef333530ae6.zip
gdb_server: improved gdb load performance
by ack'ing memory writes immediately and reporting either at next memory write or stepi/continue time. GDB will then send off a new packet that is ready by the time the previous packet has been written to target memory. On faster adapters this can be as much as 10% improvement. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Diffstat (limited to 'src/server')
-rw-r--r--src/server/gdb_server.c45
1 files changed, 37 insertions, 8 deletions
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 17ca4398..f46980e1 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -2,7 +2,7 @@
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
- * Copyright (C) 2007-2009 Øyvind Harboe *
+ * Copyright (C) 2007-2010 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
@@ -61,7 +61,12 @@ struct gdb_connection
bool sync; /* set flag to true if you want the next stepi to return immediately.
allowing GDB to pick up a fresh set of register values from the target
without modifying the target state. */
-
+ /* We delay reporting memory write errors until next step/continue or memory
+ * write. This improves performance of gdb load significantly as the GDB packet
+ * can be replied immediately and a new GDB packet will be ready without delay
+ * (ca. 10% or so...).
+ */
+ bool mem_write_error;
};
@@ -821,6 +826,7 @@ static int gdb_new_connection(struct connection *connection)
gdb_connection->busy = 0;
gdb_connection->noack_mode = 0;
gdb_connection->sync = true;
+ gdb_connection->mem_write_error = false;
/* send ACK to GDB for debug request */
gdb_write(connection, "+", 1);
@@ -1361,7 +1367,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
uint32_t addr = 0;
uint32_t len = 0;
- int retval;
+ int retval = ERROR_OK;
/* skip command character */
packet++;
@@ -1382,14 +1388,18 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
return ERROR_SERVER_REMOTE_CLOSED;
}
- retval = ERROR_OK;
- if (len)
- {
- LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+ struct gdb_connection *gdb_connection = connection->priv;
- retval = target_write_buffer(target, addr, len, (uint8_t*)separator);
+ if (gdb_connection->mem_write_error)
+ {
+ retval = ERROR_FAIL;
+ /* now that we have reported the memory write error, we can clear the condition */
+ gdb_connection->mem_write_error = false;
}
+ /* By replying the packet *immediately* GDB will send us a new packet
+ * while we write the last one to the target.
+ */
if (retval == ERROR_OK)
{
gdb_put_packet(connection, "OK", 2);
@@ -1400,6 +1410,17 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
return retval;
}
+ if (len)
+ {
+ LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+
+ retval = target_write_buffer(target, addr, len, (uint8_t*)separator);
+ if (retval != ERROR_OK)
+ {
+ gdb_connection->mem_write_error = true;
+ }
+ }
+
return ERROR_OK;
}
@@ -2211,6 +2232,14 @@ static int gdb_input_inner(struct connection *connection)
struct gdb_connection *gdb_con = connection->priv;
log_add_callback(gdb_log_callback, connection);
+ if (gdb_con->mem_write_error)
+ {
+ LOG_ERROR("Memory write failure!");
+
+ /* now that we have reported the memory write error, we can clear the condition */
+ gdb_con->mem_write_error = false;
+ }
+
bool nostep = false;
bool already_running = false;
if (target->state == TARGET_RUNNING)