public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Kevin Buettner <kevinb@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PATCH] Implement a simple "frame type" cache for Renesas RX
Date: Fri, 03 Jul 2015 02:20:00 -0000	[thread overview]
Message-ID: <20150702191958.0f5ed4c7@pinnacle.lan> (raw)

Anyone have comments regarding the change below?

My concerns are:

1) Is there an existing generic mechanism that I should be using?

2) If not, should I improve the implementation?  It wouldn't be hard
   to do, but the simple implementation shown below seems to be
   adequate for speeding things up...

Kevin

---

Implement a simple "frame type" cache for Renesas RX.

Determining the frame type (normal, exception, or fast interrupt) is
expensive when sniffing for normal frames or exception frames.  The
frame type is determined by scanning to the end of the function until
some type of return instruction is found.  The type of instruction
(RTS, RTE, RTFI) determines the type of the corresponding frame.  This
operation is especially slow when attempting to read memory over a slow
interface.

This change implements a simple 256-entry cache.  The cache is
extremely simple in that, if a collision occurs, the colliding entry
is overwritten even if there are unused entries in the table.  The
implementation could definitely be improved but even, as is, it
significantly improves the user experience.

A NULL entry for this cache is created when a new inferior is created.
The cache is actually created upon the first attempted access of the
cache.  It is freed when the inferior terminates.

gdb/ChangeLog:

	* rx-tdep.c (inferior.h): Include.
	(rx_frame_type): Add RX_FRAME_TYPE_NONE.
	(rx_frame_type_cache_key): New static global.
	(rx_frame_type cache): New struct.
	(rx_frame_type_cache_cleanup, get_rx_frame_type_cache)
	(rx_fame_type_cache_hash_index, rx_frame_type_cache_lookup)
	(rx_frame_type_cache_set): New functions.
	(rx_frame_type): Use cache.
	(_initialize_rx_tdep): Register inferior data, initializing
	rx_frame_type_cache_key.
---
 gdb/rx-tdep.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 110 insertions(+), 7 deletions(-)

diff --git a/gdb/rx-tdep.c b/gdb/rx-tdep.c
index 8442c76..43c47d9 100644
--- a/gdb/rx-tdep.c
+++ b/gdb/rx-tdep.c
@@ -20,6 +20,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "inferior.h"
 #include "arch-utils.h"
 #include "prologue-value.h"
 #include "target.h"
@@ -57,6 +58,7 @@ enum
 
 /* RX frame types.  */
 enum rx_frame_type {
+  RX_FRAME_TYPE_NONE,			/* For frame type cache. */
   RX_FRAME_TYPE_NORMAL,
   RX_FRAME_TYPE_EXCEPTION,
   RX_FRAME_TYPE_FAST_INTERRUPT
@@ -451,6 +453,80 @@ rx_analyze_frame_prologue (struct frame_info *this_frame,
   return *this_prologue_cache;
 }
 
+/* Frame Type Cache.  Scanning memory for return instructions can be
+   slow.  This is a simple cache implemention which speeds things up
+   a bit.  */
+
+static const struct inferior_data *rx_frame_type_cache_key;
+
+struct rx_frame_type_cache
+{
+  CORE_ADDR addr;
+  enum rx_frame_type frame_type;
+};
+
+/* Free data structure associated with a frame type cache.  */
+
+static void
+rx_frame_type_cache_cleanup (struct inferior *inf, void *data)
+{
+  xfree (data);
+}
+
+/* Fetch frame type cache associated with current inferior.  */
+
+static struct rx_frame_type_cache *
+get_rx_frame_type_cache (void)
+{
+  struct inferior *inf = current_inferior ();
+  struct rx_frame_type_cache *cache
+    = inferior_data (inf, rx_frame_type_cache_key);
+
+  if (cache == NULL)
+    {
+      cache = XCNEWVEC (struct rx_frame_type_cache, 256);
+      set_inferior_data (inf, rx_frame_type_cache_key, cache);
+    }
+
+  gdb_assert (cache != NULL);
+
+  return cache;
+}
+
+/* Compute hash index for address ADDR.  */
+
+static int
+rx_frame_type_cache_hash_index (CORE_ADDR addr)
+{
+  return (addr + (addr >> 8) + (addr >> 16)) & 0xff;
+}
+
+/* Look up address ADDR in the frame type cache.  Return the frame
+   type if found, otherwise return RX_FRAME_TYPE_NONE.  */
+
+static enum rx_frame_type
+rx_frame_type_cache_lookup (CORE_ADDR addr)
+{
+  struct rx_frame_type_cache *c = get_rx_frame_type_cache ()
+                                + rx_frame_type_cache_hash_index (addr);
+
+  if (c->addr == addr)
+    return c->frame_type;
+  else
+    return RX_FRAME_TYPE_NONE;
+}
+
+/* Set cache entry for address ADDR using frame type FRAME_TYPE.  */
+
+static void
+rx_frame_type_cache_set (CORE_ADDR addr, enum rx_frame_type frame_type)
+{
+  struct rx_frame_type_cache *c = get_rx_frame_type_cache ()
+                                + rx_frame_type_cache_hash_index (addr);
+  c->addr = addr;
+  c->frame_type = frame_type;
+}
+
 /* Determine type of frame by scanning the function for a return
    instruction.  */
 
@@ -462,10 +538,11 @@ rx_frame_type (struct frame_info *this_frame, void **this_cache)
   int bytes_read;
   struct rx_get_opcode_byte_handle opcode_handle;
   RX_Opcode_Decoded opc;
+  enum rx_frame_type frame_type;
 
   gdb_assert (this_cache != NULL);
 
-  /* If we have a cached value, return it.  */
+  /* If we have a cached value in the prologue cache, return it.  */
 
   if (*this_cache != NULL)
     {
@@ -474,8 +551,9 @@ rx_frame_type (struct frame_info *this_frame, void **this_cache)
       return p->frame_type;
     }
 
-  /* No cached value; scan the function.  The frame type is cached in
-     rx_analyze_prologue / rx_analyze_frame_prologue.  */
+  /* No cached value; prepare to scan the function.  The frame type is
+     cached (in the prologue cache data structure) in rx_analyze_prologue 
+     and rx_analyze_frame_prologue.  */
   
   pc = get_frame_pc (this_frame);
   
@@ -485,6 +563,16 @@ rx_frame_type (struct frame_info *this_frame, void **this_cache)
   if (!find_pc_partial_function (pc, &name, &start_pc, &lim_pc))
     lim_pc = pc + 20;
 
+  /* See if frame type has been cached in per-inferior cache for
+     lim_pc.  Return that value if found.  */
+  frame_type = rx_frame_type_cache_lookup (lim_pc);
+  if (frame_type != RX_FRAME_TYPE_NONE)
+    return frame_type;
+
+  /* Frame type has not been cached in either the prologue cache data
+     structure or the per-inferior cache.  Scan instruction stream up
+     to lim_pc for some type of return instruction.  */
+  frame_type = RX_FRAME_TYPE_NORMAL;
   while (pc < lim_pc)
     {
       opcode_handle.pc = pc;
@@ -492,16 +580,28 @@ rx_frame_type (struct frame_info *this_frame, void **this_cache)
 				     &opcode_handle);
 
       if (bytes_read <= 0 || opc.id == RXO_rts)
-	return RX_FRAME_TYPE_NORMAL;
+	{
+	  frame_type = RX_FRAME_TYPE_NORMAL;
+	  break;
+	}
       else if (opc.id == RXO_rtfi)
-	return RX_FRAME_TYPE_FAST_INTERRUPT;
+	{
+	  frame_type = RX_FRAME_TYPE_FAST_INTERRUPT;
+	  break;
+	}
       else if (opc.id == RXO_rte)
-        return RX_FRAME_TYPE_EXCEPTION;
+	{
+	  frame_type = RX_FRAME_TYPE_EXCEPTION;
+	  break;
+	}
 
       pc += bytes_read;
     }
 
-  return RX_FRAME_TYPE_NORMAL;
+  /* Cache result in the per-inferior frame type cache.  */
+  rx_frame_type_cache_set (lim_pc, frame_type);
+
+  return frame_type;
 }
 
 
@@ -1158,4 +1258,7 @@ void
 _initialize_rx_tdep (void)
 {
   register_gdbarch_init (bfd_arch_rx, rx_gdbarch_init);
+
+  rx_frame_type_cache_key
+    = register_inferior_data_with_cleanup (NULL, rx_frame_type_cache_cleanup);
 }

             reply	other threads:[~2015-07-03  2:20 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-03  2:20 Kevin Buettner [this message]
2015-07-06 16:33 ` Yao Qi
2015-07-08  0:26   ` Kevin Buettner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150702191958.0f5ed4c7@pinnacle.lan \
    --to=kevinb@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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 read-only IMAP folder(s) and NNTP newsgroup(s).