From patchwork Fri Jul 3 02:19:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Buettner X-Patchwork-Id: 7480 Received: (qmail 74851 invoked by alias); 3 Jul 2015 02:20:11 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 74824 invoked by uid 89); 3 Jul 2015 02:20:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.8 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 03 Jul 2015 02:20:02 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id 0FD6219CBF2 for ; Fri, 3 Jul 2015 02:20:01 +0000 (UTC) Received: from pinnacle.lan (ovpn-113-20.phx2.redhat.com [10.3.113.20]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t632K07Q007836 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA256 bits=256 verify=NO) for ; Thu, 2 Jul 2015 22:20:00 -0400 Date: Thu, 2 Jul 2015 19:19:58 -0700 From: Kevin Buettner To: gdb-patches@sourceware.org Subject: [PATCH] Implement a simple "frame type" cache for Renesas RX Message-ID: <20150702191958.0f5ed4c7@pinnacle.lan> MIME-Version: 1.0 X-IsSubscribed: yes 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 . */ #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); }