This is the mail archive of the gdb-patches@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]

PATCH: Circular trace buffers


This patch adds a flag that requests the target agent to make the trace buffer circular, so that instead of filling it up and then stopping, the agent discards the oldest trace frames as necessary to accommodate new ones. Any hairy memory management code is going to be on the target side; GDB just has to transmit the setting (and now always via target vector), and report back status, which may now include a total number of frames that were created. This also adds complete documentation of the qTStatus reply, per request. Any comments before I commit?

Stan

2010-03-16 Stan Shebs  <stan@codesourcery.com>
          Pedro Alves  <pedro@codesourcery.com>

       * target.h (struct target_ops): New method
       to_set_circular_trace_buffer.
       (target_set_circular_trace_buffer): New macro.
       * target.c (update_current_target): Add
       to_set_circular_trace_buffer, fix to_set_disconnected_tracing
       default behavior.
       * remote.c (remote_set_circular_trace_buffer): New function.
       (init_remote_ops): Add it to vector.
       * tracepoint.h (struct trace_status): New field traceframes_created,
       change buffer_size and buffer_free to int.
       * tracepoint.c (circular_trace_buffer): New global.
       (start_tracing): Send values of disconnected tracing and circular
       trace buffer settings.
       (set_circular_trace_buffer): New function.
       (parse_trace_state): Handle total space and frames created.
       (trace_status_command): Display total space and total frames
       created.
       (trace_save): Write out new status values.
       (parse_trace_status): Set traceframe_count, traceframes_created,
       buffer_free and buffer_size to -1 by default.
       (_initialize_tracepoint): New setshow for circular-trace-buffer.
       * NEWS: Mention the circular trace buffer option.

       [gdb/doc]
       * gdb.texinfo (Starting and Stopping Trace Experiments): Describe
       circular-trace-buffer.
       (Tracepoint Packets): Describe QTBuffer, and details of the
       qTStatus reply.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.362
diff -p -r1.362 NEWS
*** NEWS	8 Mar 2010 19:20:38 -0000	1.362
--- NEWS	16 Mar 2010 21:27:00 -0000
*************** Renesas RX			rx
*** 114,120 ****
    tracing run at the moment that it was saved.  To create a trace
    file, use "tsave <filename>", and to use it, do "target tfile
    <name>".
!   
  * Changed commands
  
  disassemble
--- 114,127 ----
    tracing run at the moment that it was saved.  To create a trace
    file, use "tsave <filename>", and to use it, do "target tfile
    <name>".
! 
!   ** Circular trace buffer
! 
!   You can ask the target agent to handle the trace buffer as a
!   circular buffer, discarding the oldest trace frames to make room for
!   newer ones, by setting circular-trace-buffer to 1.  This feature may
!   not be available for all target agents.
! 
  * Changed commands
  
  disassemble
*************** show disconnected-tracing
*** 215,220 ****
--- 222,234 ----
     loses its connection to GDB.  If 0, the target is to stop tracing
     upon disconnection.
  
+ set circular-trace-buffer
+ show circular-trace-buffer
+    If set to 1, the target is instructed to use a circular trace buffer
+    and discard the oldest trace frames instead of stopping the trace due
+    to a full trace buffer.  If set to 0, the trace stops when the buffer
+    fills up.
+ 
  set script-extension off|soft|strict
  show script-extension
     If set to "off", the debugger does not perform any script language
*************** qTV
*** 258,263 ****
--- 272,280 ----
  QTDisconnected
     Set desired tracing behavior upon disconnection.
  
+ QTBuffer:circular
+    Set the trace buffer to be linear or circular.
+ 
  qTfP, qTsP
     Get data about the tracepoints currently in use.
  
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.389
diff -p -r1.389 remote.c
*** remote.c	7 Mar 2010 14:36:44 -0000	1.389
--- remote.c	16 Mar 2010 21:27:00 -0000
*************** remote_core_of_thread (struct target_ops
*** 9659,9664 ****
--- 9659,9676 ----
  }
  
  static void
+ remote_set_circular_trace_buffer (int val)
+ {
+   struct remote_state *rs = get_remote_state ();
+ 
+   sprintf (rs->buf, "QTBuffer:circular:%x", val);
+   putpkt (rs->buf);
+   remote_get_noisy_reply (&target_buf, &target_buf_size);
+   if (strcmp (target_buf, "OK"))
+     error (_("Target does not support this command."));
+ }
+ 
+ static void
  init_remote_ops (void)
  {
    remote_ops.to_shortname = "remote";
*************** Specify the serial device it is connecte
*** 9736,9741 ****
--- 9748,9754 ----
    remote_ops.to_upload_trace_state_variables = remote_upload_trace_state_variables;
    remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
    remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
+   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
    remote_ops.to_core_of_thread = remote_core_of_thread;
  }
  
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.242
diff -p -r1.242 target.c
*** target.c	12 Mar 2010 03:54:45 -0000	1.242
--- target.c	16 Mar 2010 21:27:00 -0000
*************** update_current_target (void)
*** 659,664 ****
--- 659,665 ----
        INHERIT (to_upload_trace_state_variables, t);
        INHERIT (to_get_raw_trace_data, t);
        INHERIT (to_set_disconnected_tracing, t);
+       INHERIT (to_set_circular_trace_buffer, t);
        INHERIT (to_magic, t);
        /* Do not inherit to_memory_map.  */
        /* Do not inherit to_flash_erase.  */
*************** update_current_target (void)
*** 848,854 ****
  	    tcomplain);
    de_fault (to_set_disconnected_tracing,
  	    (void (*) (int))
! 	    tcomplain);
  #undef de_fault
  
    /* Finally, position the target-stack beneath the squashed
--- 849,858 ----
  	    tcomplain);
    de_fault (to_set_disconnected_tracing,
  	    (void (*) (int))
! 	    target_ignore);
!   de_fault (to_set_circular_trace_buffer,
! 	    (void (*) (int))
! 	    target_ignore);
  #undef de_fault
  
    /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.173
diff -p -r1.173 target.h
*** target.h	22 Feb 2010 23:35:16 -0000	1.173
--- target.h	16 Mar 2010 21:27:00 -0000
*************** struct target_ops
*** 664,669 ****
--- 664,670 ----
      /* Set the target's tracing behavior in response to unexpected
         disconnection - set VAL to 1 to keep tracing, 0 to stop.  */
      void (*to_set_disconnected_tracing) (int val);
+     void (*to_set_circular_trace_buffer) (int val);
  
      /* Return the processor core that thread PTID was last seen on.
         This information is updated only when:
*************** extern int target_search_memory (CORE_AD
*** 1359,1364 ****
--- 1360,1368 ----
  #define target_set_disconnected_tracing(val) \
    (*current_target.to_set_disconnected_tracing) (val)
  
+ #define	target_set_circular_trace_buffer(val)	\
+   (*current_target.to_set_circular_trace_buffer) (val)
+ 
  /* Command logging facility.  */
  
  #define target_log_command(p)						\
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.146
diff -p -r1.146 tracepoint.c
*** tracepoint.c	12 Mar 2010 03:54:45 -0000	1.146
--- tracepoint.c	16 Mar 2010 21:27:00 -0000
*************** char *default_collect = "";
*** 153,158 ****
--- 153,163 ----
  
  static int disconnected_tracing;
  
+ /* This variable controls whether we ask the target for a linear or
+    circular trace buffer.  */
+ 
+ static int circular_trace_buffer;
+ 
  /* ======= Important command functions: ======= */
  static void trace_actions_command (char *, int);
  static void trace_start_command (char *, int);
*************** trace_start_command (char *args, int fro
*** 1560,1565 ****
--- 1565,1573 ----
    
    /* Tell target to treat text-like sections as transparent.  */
    target_trace_set_readonly_regions ();
+   /* Set some mode flags.  */
+   target_set_disconnected_tracing (disconnected_tracing);
+   target_set_circular_trace_buffer (circular_trace_buffer);
  
    /* Now insert traps and begin collecting data.  */
    target_trace_start ();
*************** trace_status_command (char *args, int fr
*** 1649,1664 ****
  	}
      }
  
!   if (ts->traceframe_count >= 0)
      {
        printf_filtered (_("Collected %d trace frames.\n"),
  		       ts->traceframe_count);
      }
  
!   if (ts->buffer_free)
      {
!       printf_filtered (_("Trace buffer has %llu bytes free.\n"),
! 		       ts->buffer_free);
      }
  
    /* Now report on what we're doing with tfind.  */
--- 1657,1689 ----
  	}
      }
  
!   if (ts->traceframes_created >= 0)
!     {
!       printf_filtered (_("Buffer contains %d trace frames (of %d created total).\n"),
! 		       ts->traceframe_count, ts->traceframes_created);
!     }
!   else if (ts->traceframe_count >= 0)
      {
        printf_filtered (_("Collected %d trace frames.\n"),
  		       ts->traceframe_count);
      }
  
!   if (ts->buffer_free >= 0)
      {
!       if (ts->buffer_size >= 0)
! 	{
! 	  printf_filtered (_("Trace buffer has %d bytes of %d bytes free"),
! 			   ts->buffer_free, ts->buffer_size);
! 	  if (ts->buffer_size > 0)
! 	    printf_filtered (_(" (%d%% full)"),
! 			     ((int) ((((long long) (ts->buffer_size
! 						    - ts->buffer_free)) * 100)
! 				     / ts->buffer_size)));
! 	  printf_filtered (_(".\n"));
! 	}
!       else
! 	printf_filtered (_("Trace buffer has %d bytes free.\n"),
! 			 ts->buffer_free);
      }
  
    /* Now report on what we're doing with tfind.  */
*************** trace_save_command (char *args, int from
*** 2419,2428 ****
    fprintf (fp, "R %x\n", trace_regblock_size);
  
    /* Write out status of the tracing run (aka "tstatus" info).  */
!   fprintf (fp, "status %c;%s:%x;tframes:%x;tfree:%llx\n",
  	   (ts->running ? '1' : '0'),
! 	   stop_reason_names[ts->stop_reason], ts->stopping_tracepoint,
! 	   ts->traceframe_count, ts->buffer_free);
  
    /* Note that we want to upload tracepoints and save those, rather
       than simply writing out the local ones, because the user may have
--- 2444,2461 ----
    fprintf (fp, "R %x\n", trace_regblock_size);
  
    /* Write out status of the tracing run (aka "tstatus" info).  */
!   fprintf (fp, "status %c;%s:%x",
  	   (ts->running ? '1' : '0'),
!  	   stop_reason_names[ts->stop_reason], ts->stopping_tracepoint);
!   if (ts->traceframe_count >= 0)
!     fprintf (fp, ";tframes:%x", ts->traceframe_count);
!   if (ts->traceframes_created >= 0)
!     fprintf (fp, ";tcreated:%x", ts->traceframes_created);
!   if (ts->buffer_free >= 0)
!     fprintf (fp, ";tfree:%x", ts->buffer_free);
!   if (ts->buffer_size >= 0)
!     fprintf (fp, ";tsize:%x", ts->buffer_size);
!   fprintf (fp, "\n");
  
    /* Note that we want to upload tracepoints and save those, rather
       than simply writing out the local ones, because the user may have
*************** set_disconnected_tracing (char *args, in
*** 2527,2532 ****
--- 2560,2572 ----
    send_disconnected_tracing_value (disconnected_tracing);
  }
  
+ static void
+ set_circular_trace_buffer (char *args, int from_tty,
+ 			   struct cmd_list_element *c)
+ {
+   target_set_circular_trace_buffer (circular_trace_buffer);
+ }
+ 
  /* Convert the memory pointed to by mem into hex, placing result in buf.
   * Return a pointer to the last char put in buf (null)
   * "stolen" from sparc-stub.c
*************** parse_trace_status (char *line, struct t
*** 3040,3045 ****
--- 3080,3090 ----
    ts->running_known = 1;
    ts->running = (*p++ == '1');
    ts->stop_reason = trace_stop_reason_unknown;
+   ts->traceframe_count = -1;
+   ts->traceframes_created = -1;
+   ts->buffer_free = -1;
+   ts->buffer_size = -1;
+ 
    while (*p++)
      {
        p1 = strchr (p, ':');
*************** Status line: '%s'\n"), p, line);
*** 3067,3082 ****
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->stop_reason = tstop_command;
  	}
!       if (strncmp (p, "tframes", p1 - p) == 0)
  	{
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->traceframe_count = val;
  	}
!       if (strncmp (p, "tfree", p1 - p) == 0)
  	{
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->buffer_free = val;
  	}
        else
  	{
  	  /* Silently skip unknown optional info.  */
--- 3112,3137 ----
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->stop_reason = tstop_command;
  	}
!       else if (strncmp (p, "tframes", p1 - p) == 0)
  	{
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->traceframe_count = val;
  	}
!       else if (strncmp (p, "tcreated", p1 - p) == 0)
! 	{
! 	  p = unpack_varlen_hex (++p1, &val);
! 	  ts->traceframes_created = val;
! 	}
!       else if (strncmp (p, "tfree", p1 - p) == 0)
  	{
  	  p = unpack_varlen_hex (++p1, &val);
  	  ts->buffer_free = val;
  	}
+       else if (strncmp (p, "tsize", p1 - p) == 0)
+ 	{
+ 	  p = unpack_varlen_hex (++p1, &val);
+ 	  ts->buffer_size = val;
+ 	}
        else
  	{
  	  /* Silently skip unknown optional info.  */
*************** trace data collected in the meantime."),
*** 3800,3805 ****
--- 3855,3872 ----
  			   &setlist,
  			   &showlist);
  
+   add_setshow_boolean_cmd ("circular-trace-buffer", no_class,
+ 			   &circular_trace_buffer, _("\
+ Set target's use of circular trace buffer."), _("\
+ Show target's use of circular trace buffer."), _("\
+ Use this to make the trace buffer into a circular buffer,\n\
+ which will discard traceframes (oldest first) instead of filling\n\
+ up and stopping the trace run."),
+ 			   set_circular_trace_buffer,
+ 			   NULL,
+ 			   &setlist,
+ 			   &showlist);
+ 
    init_tfile_ops ();
  
    add_target (&tfile_ops);
Index: tracepoint.h
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.h,v
retrieving revision 1.22
diff -p -r1.22 tracepoint.h
*** tracepoint.h	24 Feb 2010 01:06:28 -0000	1.22
--- tracepoint.h	16 Mar 2010 21:27:00 -0000
*************** struct trace_status
*** 95,105 ****
  
    int stopping_tracepoint;
  
    int traceframe_count;
  
!   unsigned long long buffer_size;
  
!   unsigned long long buffer_free;
  };
  
  struct trace_status *current_trace_status (void);
--- 95,115 ----
  
    int stopping_tracepoint;
  
+   /* Number of traceframes currently in the buffer.  */
+ 
    int traceframe_count;
  
!   /* Number of traceframes created since start of run.  */
! 
!   int traceframes_created;
! 
!   /* Total size of the target's trace buffer.  */
! 
!   int buffer_size;
! 
!   /* Unused bytes left in the target's trace buffer.  */
  
!   int buffer_free;
  };
  
  struct trace_status *current_trace_status (void);
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.680
diff -p -r1.680 gdb.texinfo
*** doc/gdb.texinfo	12 Mar 2010 19:15:52 -0000	1.680
--- doc/gdb.texinfo	16 Mar 2010 21:27:01 -0000
*************** which to specify that tracepoint.  This 
*** 9836,9841 ****
--- 9836,9868 ----
  necessarily heuristic, and it may result in useless tracepoints being
  created; you may simply delete them if they are of no use.
  
+ @cindex circular trace buffer
+ If your target agent supports a @dfn{circular trace buffer}, then you
+ can run a trace experiment indefinitely without filling the trace
+ buffer; when space runs out, the agent deletes already-collected trace
+ frames, oldest first, until there is enough room to continue
+ collecting.  This is especially useful if your tracepoints are being
+ hit too often and terminating tracing too soon.  To ask for a circular
+ trace buffer, simply set @samp{circular_trace_buffer} to 1.  You can
+ set this at any time, including during tracing; if the agent can do
+ it, it will change buffer handling on the fly, otherwise it will not
+ take effect until the next run.
+ 
+ @table @code
+ @item set circular-trace-buffer on
+ @itemx set circular-trace-buffer off
+ @kindex set circular-trace-buffer
+ Choose whether a tracing run should use a linear or circular buffer
+ for trace data.  A linear buffer will not lose any trace data, but may
+ fill up prematurely, while a circular buffer will discard old trace
+ data, but it will have always room for the latest tracepoint hits.
+ 
+ @item show circular-trace-buffer
+ @kindex show circular-trace-buffer
+ Show the current choice for the trace buffer.
+ 
+ @end table
+ 
  @node Tracepoint Restrictions
  @subsection Tracepoint Restrictions
  
*************** encoded).  @value{GDBN} will continue to
*** 30603,30608 ****
--- 30630,30636 ----
  @end table
  
  @item qTBuffer
+ @item QTBuffer
  @item QTDisconnected
  @itemx QTDP
  @itemx QTDV
*************** continue the tracing run, while 0 tells 
*** 31087,31098 ****
  @item qTStatus
  Ask the stub if there is a trace experiment running right now.
  
! Replies:
  @table @samp
! @item T0
! There is no trace experiment running.
! @item T1
! There is a trace experiment running.
  @end table
  
  @item qTV:@var{var}
--- 31115,31176 ----
  @item qTStatus
  Ask the stub if there is a trace experiment running right now.
  
! The reply has the form:
! 
! @table @samp
! 
! @item T@var{running}@r{[};@var{field}@r{]}@dots{}
! @var{running} is a single digit @code{1} if the trace is presently
! running, or @code{0} if not.  It is followed by optional fields that
! an agent may use to report additional status. 
! 
! @end table
! 
! If the trace is not running, the agent may report any of several
! explanations as one of the optional fields:
! 
! @table @samp
! 
! @item tnotrun:0
! No trace has been run yet.
! 
! @item tstop:0
! The trace was stopped by a user-originated stop command.
! 
! @item tfull:0
! The trace stopped because the trace buffer filled up.
! 
! @item tdisconnected:0
! The trace stopped because @value{GDBN} disconnected from the target.
! 
! @item tpasscount:@var{tpnum}
! The trace stopped because tracepoint @var{tpnum} exceeded its pass count.
! 
! @item tunknown:0
! The trace stopped for some other reason.
! 
! @end table
! 
! Additional optional fields supply statistical information.  Although
! not required, they are extremely useful for users monitoring the
! progress of a trace run.  If a trace has stopped, and these numbers
! are reported, they must reflect the state of the just-stopped trace.
! 
  @table @samp
! 
! @item tframes:@var{n}
! The number of trace frames in the buffer.
! 
! @item tcreated:@var{n}
! The total number of trace frames created during the run. This may
! be larger than the trace frame count, if the buffer is circular.
! 
! @item tsize:@var{n}
! The total size of the trace buffer.
! 
! @item tfree:@var{n}
! The number of bytes still unused in the buffer.
! 
  @end table
  
  @item qTV:@var{var}
*************** in a packet; it is not an error to retur
*** 31147,31152 ****
--- 31225,31234 ----
  A reply consisting of just @code{l} indicates that no bytes are
  available.
  
+ @item QTBuffer:circular:@var{value}
+ This packet directs the target to use a circular trace buffer if
+ @var{value} is 1, or a linear buffer if the value is 0.
+ 
  @end table
  
  @node Host I/O Packets

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