From 80152258b9dfe033828e5c5b6dc3252be1ba7a84 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 21 Aug 2015 10:13:27 +0100 Subject: [PATCH] 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 * remote.c (struct readahead_cache): New. (struct remote_state) : 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. --- gdb/ChangeLog | 14 ++++++ gdb/remote.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 149 insertions(+), 4 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3f2bb37..e7cd74c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2015-08-21 Pedro Alves + + * remote.c (struct readahead_cache): New. + (struct remote_state) : 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 (tiny patch) PR build/18843 diff --git a/gdb/remote.c b/gdb/remote.c index 89f7faf..068d079 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -228,6 +228,8 @@ static void remote_btrace_reset (void); static int stop_reply_queue_length (void); +static void readahead_cache_invalidate (void); + /* For "remote". */ static struct cmd_list_element *remote_cmdlist; @@ -264,6 +266,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. */ @@ -383,6 +408,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. */ @@ -4561,6 +4594,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. */ @@ -10400,6 +10435,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). */ @@ -10478,6 +10534,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); @@ -10493,12 +10551,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; @@ -10532,6 +10591,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 @@ -10541,6 +10670,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); -- 2.7.4