Re: JIT debugging (Attach and speed)

Pedro Alves <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
On 03/23/2016 08:51 PM, Yichao Yu wrote:

> Also, it looks like gdb is trying to get info about the current frame?
> Can this be disabled for this breakpoint since it's not a "real" one?

Excellent suggestion.  Seems like we can avoid computing a
frame unless we're stepping, or presenting a stop.

The prototype patch below (also in users/palves/jit-speedup, along
with the attach fixes), simply delays computing a frame until
it's necessary, and it cuts down the time for:

  gdb ---args ./testsuite/outputs/gdb.base/jit/jit-main ./testsuite/outputs/gdb.base/jit/jit-solib.so 2000

from "takes too long so I canceled it" minutes, to around 2 seconds, for me.

There's one hack though -- I commented out the skip_inline_frames
call...  We'll need to handle that some other way, or in some
other place.  As is, this regresses some inline tests, naturally...

Having a pending breakpoint that is never resolved slows things down
significantly again though...  The perf profile shows that breakpoint_re_set
ends up calling parse_linespec which wants the selected block, which wants
the selected frame, and then we're back at the same...  Maybe we
could reconsider how pending breakpoints are re-parsed, and which
context they're parsed in.  Not sure.

Still, very promising.

-----------
From a1e599495aafd10ae0505558343136f90b291038 Mon Sep 17 00:00:00 2001
From: Pedro Alves <[email protected]>
Date: Wed, 23 Mar 2016 18:11:45 +0000
Subject: [PATCH] Avoid creating a frame in internal stops

This speeds up JIT library loading by ${a lot}.
---
 gdb/breakpoint.c |  3 +-
 gdb/infrun.c     | 98 ++++++++++++++++++++++++++++++--------------------------
 2 files changed, 54 insertions(+), 47 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f99a7ab..ed708a9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5792,8 +5792,7 @@ handle_jit_event (void)
      breakpoint_re_set.  */
   target_terminal_ours_for_output ();
 -  frame = get_current_frame ();
-  gdbarch = get_frame_arch (frame);
+  gdbarch = get_regcache_arch (get_current_regcache ());
    jit_event_handler (gdbarch);
 diff --git a/gdb/infrun.c b/gdb/infrun.c
index 696105d..6067cb0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5608,8 +5608,6 @@ finish_step_over (struct execution_control_state *ecs)
 static void
 handle_signal_stop (struct execution_control_state *ecs)
 {
-  struct frame_info *frame;
-  struct gdbarch *gdbarch;
   int stopped_by_watchpoint;
   enum stop_kind stop_soon;
   int random_signal;
@@ -5717,10 +5715,6 @@ handle_signal_stop (struct execution_control_state *ecs)
 	deprecated_context_hook (ptid_to_global_thread_id (ecs->ptid));
     }
 -  /* At this point, get hold of the now-current thread's frame.  */
-  frame = get_current_frame ();
-  gdbarch = get_frame_arch (frame);
-
   /* Pull the single step breakpoints out of the target.  */
   if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
     {
@@ -5774,7 +5768,7 @@ handle_signal_stop (struct execution_control_state *ecs)
      it in a moment.  */
   if (stopped_by_watchpoint
       && (target_have_steppable_watchpoint
-	  || gdbarch_have_nonsteppable_watchpoint (gdbarch)))
+	  || gdbarch_have_nonsteppable_watchpoint (get_regcache_arch (get_current_regcache ()))))
     {
       /* At this point, we are stopped at an instruction which has
          attempted to write to a piece of memory under control of
@@ -5838,27 +5832,25 @@ handle_signal_stop (struct execution_control_state *ecs)
 	 user had set a breakpoint on that inlined code, the missing
 	 skip_inline_frames call would break things.  Fortunately
 	 that's an extremely unlikely scenario.  */
+#if 0
       if (!pc_at_non_inline_function (aspace, stop_pc, &ecs->ws)
 	  && !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
 	       && ecs->event_thread->control.trap_expected
 	       && pc_at_non_inline_function (aspace,
 					     ecs->event_thread->prev_pc,
 					     &ecs->ws)))
-	{
-	  skip_inline_frames (ecs->ptid);
-
-	  /* Re-fetch current thread's frame in case that invalidated
-	     the frame cache.  */
-	  frame = get_current_frame ();
-	  gdbarch = get_frame_arch (frame);
-	}
+	skip_inline_frames (ecs->ptid);
+#endif
     }
    if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
       && ecs->event_thread->control.trap_expected
-      && gdbarch_single_step_through_delay_p (gdbarch)
+      && gdbarch_single_step_through_delay_p (get_regcache_arch (get_current_regcache ()))
       && currently_stepping (ecs->event_thread))
     {
+      struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
+      struct frame_info *frame = get_current_frame ();
+
       /* We're trying to step off a breakpoint.  Turns out that we're
 	 also on an instruction that needs to be stepped multiple
 	 times before it's been fully executing.  E.g., architectures
@@ -5946,6 +5938,9 @@ handle_signal_stop (struct execution_control_state *ecs)
      been removed.  */
   if (random_signal && target_stopped_by_sw_breakpoint ())
     {
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+
       if (program_breakpoint_here_p (gdbarch, stop_pc))
 	{
 	  struct regcache *regcache;
@@ -6051,6 +6046,7 @@ handle_signal_stop (struct execution_control_state *ecs)
 	  && ecs->event_thread->control.trap_expected
 	  && ecs->event_thread->control.step_resume_breakpoint == NULL)
 	{
+	  struct frame_info *frame = get_current_frame ();
 	  int was_in_line;
  	  /* We were just starting a new sequence, attempting to
@@ -6105,11 +6101,14 @@ handle_signal_stop (struct execution_control_state *ecs)
        if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
 	  && (pc_in_thread_step_range (stop_pc, ecs->event_thread)
-	      || ecs->event_thread->control.step_range_end == 1)
-	  && frame_id_eq (get_stack_frame_id (frame),
-			  ecs->event_thread->control.step_stack_frame_id)
-	  && ecs->event_thread->control.step_resume_breakpoint == NULL)
+	      || ecs->event_thread->control.step_range_end == 1))
 	{
+	  struct frame_info *frame = get_current_frame ();
+
+	  if (frame_id_eq (get_stack_frame_id (frame),
+			   ecs->event_thread->control.step_stack_frame_id)
+	      && ecs->event_thread->control.step_resume_breakpoint == NULL)
+	    {
 	  /* The inferior is about to take a signal that will take it
 	     out of the single step range.  Set a breakpoint at the
 	     current PC (which is presumably where the signal handler
@@ -6131,6 +6130,7 @@ handle_signal_stop (struct execution_control_state *ecs)
 	  ecs->event_thread->control.trap_expected = 0;
 	  keep_going (ecs);
 	  return;
+	    }
 	}
        /* Note: step_resume_breakpoint may be non-NULL.  This occures
@@ -6164,16 +6164,11 @@ static void
 process_event_stop_test (struct execution_control_state *ecs)
 {
   struct symtab_and_line stop_pc_sal;
-  struct frame_info *frame;
-  struct gdbarch *gdbarch;
   CORE_ADDR jmp_buf_pc;
   struct bpstat_what what;
    /* Handle cases caused by hitting a breakpoint.  */
 -  frame = get_current_frame ();
-  gdbarch = get_frame_arch (frame);
-
   what = bpstat_what (ecs->event_thread->control.stop_bpstat);
    if (what.call_dummy)
@@ -6185,12 +6180,6 @@ process_event_stop_test (struct execution_control_state *ecs)
      bp_jit_event).  Run them now.  */
   bpstat_run_callbacks (ecs->event_thread->control.stop_bpstat);
 -  /* If we hit an internal event that triggers symbol changes, the
-     current frame will be invalidated within bpstat_what (e.g., if we
-     hit an internal solib event).  Re-fetch it.  */
-  frame = get_current_frame ();
-  gdbarch = get_frame_arch (frame);
-
   switch (what.main_action)
     {
     case BPSTAT_WHAT_SET_LONGJMP_RESUME:
@@ -6207,6 +6196,8 @@ process_event_stop_test (struct execution_control_state *ecs)
       if (what.is_longjmp)
 	{
 	  struct value *arg_value;
+	  struct frame_info *frame = get_current_frame ();
+	  struct gdbarch *gdbarch = get_frame_arch (frame);
  	  /* If we set the longjmp breakpoint via a SystemTap probe,
 	     then use it to extract the arguments.  The destination PC
@@ -6233,7 +6224,11 @@ process_event_stop_test (struct execution_control_state *ecs)
 	  insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
 	}
       else
-	check_exception_resume (ecs, frame);
+	{
+	  struct frame_info *frame = get_current_frame ();
+
+	  check_exception_resume (ecs, frame);
+	}
       keep_going (ecs);
       return;
 @@ -6333,7 +6328,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	  keep_going (ecs);
 	  return;
 	}
-      fill_in_stop_func (gdbarch, ecs);
+      fill_in_stop_func (get_regcache_arch (get_current_regcache ()), ecs);
       if (stop_pc == ecs->stop_func_start
 	  && execution_direction == EXEC_REVERSE)
 	{
@@ -6450,12 +6445,7 @@ process_event_stop_test (struct execution_control_state *ecs)
       return;
     }
 -  /* Re-fetch current thread's frame in case the code above caused
-     the frame cache to be re-initialized, making our FRAME variable
-     a dangling pointer.  */
-  frame = get_current_frame ();
-  gdbarch = get_frame_arch (frame);
-  fill_in_stop_func (gdbarch, ecs);
+  fill_in_stop_func (get_regcache_arch (get_current_regcache ()), ecs);
    /* If stepping through a line, keep going if still within it.
 @@ -6469,9 +6459,11 @@ process_event_stop_test (struct execution_control_state *ecs)
    if (pc_in_thread_step_range (stop_pc, ecs->event_thread)
       && (execution_direction != EXEC_REVERSE
-	  || frame_id_eq (get_frame_id (frame),
+	  || frame_id_eq (get_frame_id (get_current_frame ()),
 			  ecs->event_thread->control.step_frame_id)))
     {
+      struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
+
       if (debug_infrun)
 	fprintf_unfiltered
 	  (gdb_stdlog, "infrun: stepping inside range [%s-%s]\n",
@@ -6514,6 +6506,7 @@ process_event_stop_test (struct execution_control_state *ecs)
       && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
       && in_solib_dynsym_resolve_code (stop_pc))
     {
+      struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
       CORE_ADDR pc_after_resolver =
 	gdbarch_skip_solib_resolver (gdbarch, stop_pc);
 @@ -6529,7 +6522,7 @@ process_event_stop_test (struct execution_control_state *ecs)
  	  init_sal (&sr_sal);
 	  sr_sal.pc = pc_after_resolver;
-	  sr_sal.pspace = get_frame_program_space (frame);
+	  sr_sal.pspace = current_program_space;
  	  insert_step_resume_breakpoint_at_sal (gdbarch,
 						sr_sal, null_frame_id);
@@ -6542,7 +6535,7 @@ process_event_stop_test (struct execution_control_state *ecs)
   if (ecs->event_thread->control.step_range_end != 1
       && (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
 	  || ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
-      && get_frame_type (frame) == SIGTRAMP_FRAME)
+      && get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME)
     {
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog,
@@ -6561,12 +6554,14 @@ process_event_stop_test (struct execution_control_state *ecs)
   /* macro/2012-04-25: This needs to come before the subroutine
      call check below as on some targets return trampolines look
      like subroutine calls (MIPS16 return thunks).  */
-  if (gdbarch_in_solib_return_trampoline (gdbarch,
+  if (gdbarch_in_solib_return_trampoline (get_regcache_arch (get_current_regcache ()),
 					  stop_pc, ecs->stop_func_name)
       && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
     {
       /* Determine where this trampoline returns.  */
       CORE_ADDR real_stop_pc;
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
        real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
 @@ -6615,7 +6610,7 @@ process_event_stop_test (struct execution_control_state *ecs)
      initial outermost frame, before sp was valid, would
      have code_addr == &_start.  See the comment in frame_id_eq
      for more.  */
-  if (!frame_id_eq (get_stack_frame_id (frame),
+  if (!frame_id_eq (get_stack_frame_id (get_current_frame ()),
 		    ecs->event_thread->control.step_stack_frame_id)
       && (frame_id_eq (frame_unwind_caller_id (get_current_frame ()),
 		       ecs->event_thread->control.step_stack_frame_id)
@@ -6625,6 +6620,8 @@ process_event_stop_test (struct execution_control_state *ecs)
 		  != find_pc_function (stop_pc)))))
     {
       CORE_ADDR real_stop_pc;
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
        if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
@@ -6787,6 +6784,9 @@ process_event_stop_test (struct execution_control_state *ecs)
   if (execution_direction == EXEC_REVERSE
       && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
     {
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+
       if (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc)
 	  || (ecs->stop_func_start == 0
 	      && in_solib_dynsym_resolve_code (stop_pc)))
@@ -6825,6 +6825,9 @@ process_event_stop_test (struct execution_control_state *ecs)
       && ecs->stop_func_name == NULL
       && stop_pc_sal.line == 0)
     {
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog,
 			     "infrun: stepped into undebuggable function\n");
@@ -6969,7 +6972,12 @@ process_event_stop_test (struct execution_control_state *ecs)
   ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
-  set_step_info (frame, stop_pc_sal);
+
+  {
+      struct frame_info *frame = get_current_frame ();
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+      set_step_info (frame, stop_pc_sal);
+  }
    if (debug_infrun)
      fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
-- 
2.5.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.