This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb/gdb-7.10-branch] Add readahead cache to gdb's vFile:pread


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ed54cc2eb010be3134138590861f6175449447e0

commit ed54cc2eb010be3134138590861f6175449447e0
Author: Pedro Alves <palves@redhat.com>
Date:   Fri Aug 21 10:25:43 2015 +0100

    Add readahead cache to gdb's vFile:pread
    
    This patch almost halves the time it takes to "target remote + run to
    main" on a higher-latency connection.
    
    E.g., I've got a ping time of ~85ms to an x86-64 machine on the gcc
    compile farm (almost 2000km away from me), and I'm behind a ~16Mbit
    ADSL.  When I connect to a gdbserver debugging itself on that machine
    and run to main, it takes almost 55 seconds:
    
     [palves@gcc76] $ ./gdbserver :9999 ./gdbserver
     [palves@home] $ ssh -L 9999:localhost:9999 gcc76.fsffrance.org
     [palves@home] $ time ./gdb -data-directory=data-directory -ex "tar rem :9999" -ex "b main" -ex "c" -ex "set confirm off" -ex "quit"
    
     Pristine gdb 7.10.50.20150820-cvs gets us:
     ...
     Remote debugging using :9999
     Reading symbols from target:/home/palves/gdb/build/gdb/gdbserver/gdbserver...done.
     Reading symbols from target:/lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
     0x00007ffff7ddd190 in ?? () from target:/lib64/ld-linux-x86-64.so.2
     Breakpoint 1 at 0x41200c: file ../../../src/gdb/gdbserver/server.c, line 3635.
     Continuing.
    
     Breakpoint 1, main (argc=1, argv=0x7fffffffe3d8) at ../../../src/gdb/gdbserver/server.c:3635
     3635    ../../../src/gdb/gdbserver/server.c: No such file or directory.
     /home/palves/gdb/build/gdb/gdbserver/gdbserver: No such file or directory.
    
     real    0m54.803s
     user    0m0.329s
     sys     0m0.064s
    
    While with the readahead cache added by this patch, it drops to:
    
     real    0m29.462s
     user    0m0.454s
     sys     0m0.054s
    
    I added a few counters to show cache hit/miss, and got:
    
     readahead cache miss 142
     readahead cache hit 310
    
    Tested on x86_64 Fedora 20.
    
    gdb/ChangeLog:
    2015-08-21  Pedro Alves  <palves@redhat.com>
    
    	* remote.c (struct readahead_cache): New.
    	(struct remote_state) <readahead_cache>: New field.
    	(remote_open_1): Invalidate the cache.
    	(readahead_cache_invalidate, readahead_cache_invalidate_fd): New
    	functions.
    	(remote_hostio_pwrite): Invalidate the readahead cache.
    	(remote_hostio_pread): Rename to ...
    	(remote_hostio_pread_vFile): ... this.
    	(remote_hostio_pread_from_cache): New function.
    	(remote_hostio_pread): Reimplement.
    	(remote_hostio_close): Invalidate the readahead cache.

Diff:
---
 gdb/ChangeLog |  14 ++++++
 gdb/remote.c  | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 149 insertions(+), 4 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4302997..d2a6cbc 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@
+2015-08-21  Pedro Alves  <palves@redhat.com>
+
+	* remote.c (struct readahead_cache): New.
+	(struct remote_state) <readahead_cache>: New field.
+	(remote_open_1): Invalidate the cache.
+	(readahead_cache_invalidate, readahead_cache_invalidate_fd): New
+	functions.
+	(remote_hostio_pwrite): Invalidate the readahead cache.
+	(remote_hostio_pread): Rename to ...
+	(remote_hostio_pread_vFile): ... this.
+	(remote_hostio_pread_from_cache): New function.
+	(remote_hostio_pread): Reimplement.
+	(remote_hostio_close): Invalidate the readahead cache.
+
 2015-08-21  Marcin CieÅ?lak <saper@saper.info>  (tiny patch)
 
 	PR build/18843
diff --git a/gdb/remote.c b/gdb/remote.c
index 7a85dd9..c5ec2c7 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -224,6 +224,8 @@ static int remote_can_run_breakpoint_commands (struct target_ops *self);
 
 static void remote_btrace_reset (void);
 
+static void readahead_cache_invalidate (void);
+
 /* For "remote".  */
 
 static struct cmd_list_element *remote_cmdlist;
@@ -260,6 +262,29 @@ typedef unsigned char threadref[OPAQUETHREADBYTES];
 
 #define MAXTHREADLISTRESULTS 32
 
+/* Data for the vFile:pread readahead cache.  */
+
+struct readahead_cache
+{
+  /* The file descriptor for the file that is being cached.  -1 if the
+     cache is invalid.  */
+  int fd;
+
+  /* The offset into the file that the cache buffer corresponds
+     to.  */
+  ULONGEST offset;
+
+  /* The buffer holding the cache contents.  */
+  gdb_byte *buf;
+  /* The buffer's size.  We try to read as much as fits into a packet
+     at a time.  */
+  size_t bufsize;
+
+  /* Cache hit and miss counters.  */
+  ULONGEST hit_count;
+  ULONGEST miss_count;
+};
+
 /* Description of the remote protocol state for the currently
    connected target.  This is per-target state, and independent of the
    selected architecture.  */
@@ -379,6 +404,14 @@ struct remote_state
      Initialized to -1 to indicate that no "vFile:setfs:" packet
      has yet been sent.  */
   int fs_pid;
+
+  /* A readahead cache for vFile:pread.  Often, reading a binary
+     involves a sequence of small reads.  E.g., when parsing an ELF
+     file.  A readahead cache helps mostly the case of remote
+     debugging on a connection with higher latency, due to the
+     request/reply nature of the RSP.  We only cache data for a single
+     file descriptor at a time.  */
+  struct readahead_cache readahead_cache;
 };
 
 /* Private data that we'll store in (struct thread_info)->private.  */
@@ -4472,6 +4505,8 @@ remote_open_1 (const char *name, int from_tty,
   rs->use_threadinfo_query = 1;
   rs->use_threadextra_query = 1;
 
+  readahead_cache_invalidate ();
+
   if (target_async_permitted)
     {
       /* With this target we start out by owning the terminal.  */
@@ -10273,6 +10308,27 @@ remote_hostio_send_command (int command_bytes, int which_packet,
   return ret;
 }
 
+/* Invalidate the readahead cache.  */
+
+static void
+readahead_cache_invalidate (void)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  rs->readahead_cache.fd = -1;
+}
+
+/* Invalidate the readahead cache if it is holding data for FD.  */
+
+static void
+readahead_cache_invalidate_fd (int fd)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  if (rs->readahead_cache.fd == fd)
+    rs->readahead_cache.fd = -1;
+}
+
 /* Set the filesystem remote_hostio functions that take FILENAME
    arguments will use.  Return 0 on success, or -1 if an error
    occurs (and set *REMOTE_ERRNO).  */
@@ -10351,6 +10407,8 @@ remote_hostio_pwrite (struct target_ops *self,
   int left = get_remote_packet_size ();
   int out_len;
 
+  readahead_cache_invalidate_fd (fd);
+
   remote_buffer_add_string (&p, &left, "vFile:pwrite:");
 
   remote_buffer_add_int (&p, &left, fd);
@@ -10366,12 +10424,13 @@ remote_hostio_pwrite (struct target_ops *self,
 				     remote_errno, NULL, NULL);
 }
 
-/* Implementation of to_fileio_pread.  */
+/* Helper for the implementation of to_fileio_pread.  Read the file
+   from the remote side with vFile:pread.  */
 
 static int
-remote_hostio_pread (struct target_ops *self,
-		     int fd, gdb_byte *read_buf, int len,
-		     ULONGEST offset, int *remote_errno)
+remote_hostio_pread_vFile (struct target_ops *self,
+			   int fd, gdb_byte *read_buf, int len,
+			   ULONGEST offset, int *remote_errno)
 {
   struct remote_state *rs = get_remote_state ();
   char *p = rs->buf;
@@ -10405,6 +10464,76 @@ remote_hostio_pread (struct target_ops *self,
   return ret;
 }
 
+/* Serve pread from the readahead cache.  Returns number of bytes
+   read, or 0 if the request can't be served from the cache.  */
+
+static int
+remote_hostio_pread_from_cache (struct remote_state *rs,
+				int fd, gdb_byte *read_buf, size_t len,
+				ULONGEST offset)
+{
+  struct readahead_cache *cache = &rs->readahead_cache;
+
+  if (cache->fd == fd
+      && cache->offset <= offset
+      && offset < cache->offset + cache->bufsize)
+    {
+      ULONGEST max = cache->offset + cache->bufsize;
+
+      if (offset + len > max)
+	len = max - offset;
+
+      memcpy (read_buf, cache->buf + offset - cache->offset, len);
+      return len;
+    }
+
+  return 0;
+}
+
+/* Implementation of to_fileio_pread.  */
+
+static int
+remote_hostio_pread (struct target_ops *self,
+		     int fd, gdb_byte *read_buf, int len,
+		     ULONGEST offset, int *remote_errno)
+{
+  int ret;
+  struct remote_state *rs = get_remote_state ();
+  struct readahead_cache *cache = &rs->readahead_cache;
+
+  ret = remote_hostio_pread_from_cache (rs, fd, read_buf, len, offset);
+  if (ret > 0)
+    {
+      cache->hit_count++;
+
+      if (remote_debug)
+	fprintf_unfiltered (gdb_stdlog, "readahead cache hit %s\n",
+			    pulongest (cache->hit_count));
+      return ret;
+    }
+
+  cache->miss_count++;
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "readahead cache miss %s\n",
+			pulongest (cache->miss_count));
+
+  cache->fd = fd;
+  cache->offset = offset;
+  cache->bufsize = get_remote_packet_size ();
+  cache->buf = xrealloc (cache->buf, cache->bufsize);
+
+  ret = remote_hostio_pread_vFile (self, cache->fd, cache->buf, cache->bufsize,
+				   cache->offset, remote_errno);
+  if (ret <= 0)
+    {
+      readahead_cache_invalidate_fd (fd);
+      return ret;
+    }
+
+  cache->bufsize = ret;
+  return remote_hostio_pread_from_cache (rs, fd, read_buf, len, offset);
+}
+
 /* Implementation of to_fileio_close.  */
 
 static int
@@ -10414,6 +10543,8 @@ remote_hostio_close (struct target_ops *self, int fd, int *remote_errno)
   char *p = rs->buf;
   int left = get_remote_packet_size () - 1;
 
+  readahead_cache_invalidate_fd (fd);
+
   remote_buffer_add_string (&p, &left, "vFile:close:");
 
   remote_buffer_add_int (&p, &left, fd);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]