2010-03-18 Stan Shebs <stan@codesourcery.com>
authorStan Shebs <shebs@codesourcery.com>
Thu, 18 Mar 2010 21:23:35 +0000 (21:23 +0000)
committerStan Shebs <shebs@codesourcery.com>
Thu, 18 Mar 2010 21:23:35 +0000 (21:23 +0000)
    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.texinfo (Starting and Stopping Trace Experiments): Describe
circular-trace-buffer.
(Tracepoint Packets): Describe QTBuffer, and details of the
qTStatus reply.

* gdb.trace/circ.exp: Test circular-trace-buffer.
* gdb.trace/tfile.exp: Update tstatus test.

12 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/remote.c
gdb/target.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/circ.exp
gdb/testsuite/gdb.trace/tfile.exp
gdb/tracepoint.c
gdb/tracepoint.h

index 2cf42aa..55462bb 100644 (file)
@@ -1,3 +1,29 @@
+2010-03-18  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.
+
 2010-03-18  Tom Tromey  <tromey@redhat.com>
 
        * infcmd.c (finish_command_continuation): Wrap print_return_value
index 64c48f6..ff4e4af 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -114,7 +114,14 @@ Renesas RX                 rx
   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 on.  This feature may
+  not be available for all target agents.
+
 * Changed commands
 
 disassemble
@@ -215,6 +222,13 @@ show disconnected-tracing
    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 on, 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 off, the trace stops when the buffer
+   fills up.  Some targets may not support this.
+
 set script-extension off|soft|strict
 show script-extension
    If set to "off", the debugger does not perform any script language
@@ -258,6 +272,9 @@ qTV
 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 7a9590e..e85827b 100644 (file)
@@ -1,3 +1,10 @@
+2010-03-16  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Starting and Stopping Trace Experiments): Describe
+       circular-trace-buffer.
+       (Tracepoint Packets): Describe QTBuffer, and details of the
+       qTStatus reply.
+
 2010-03-12  Stan Shebs  <stan@codesourcery.com>
            Nathan Sidwell  <nathan@codesourcery.com>
 
index 53989bb..92a1237 100644 (file)
@@ -9836,6 +9836,37 @@ which to specify that tracepoint.  This matching-up process is
 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 your trace gets terminated prematurely because the
+buffer is full.  To ask for a circular trace buffer, simply set
+@samp{circular_trace_buffer} to on.  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.  Note that this may not
+match the agent's current buffer handling, nor is it guaranteed to
+match the setting that might have been in effect during a past run,
+for instance if you are looking at frames from a trace file.
+
+@end table
+
 @node Tracepoint Restrictions
 @subsection Tracepoint Restrictions
 
@@ -30603,6 +30634,7 @@ encoded).  @value{GDBN} will continue to supply the values of symbols
 @end table
 
 @item qTBuffer
+@item QTBuffer
 @item QTDisconnected
 @itemx QTDP
 @itemx QTDV
@@ -31087,12 +31119,62 @@ continue the tracing run, while 0 tells the target to stop tracing if
 @item qTStatus
 Ask the stub if there is a trace experiment running right now.
 
-Replies:
+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 semicolon-separated
+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 T0
-There is no trace experiment running.
-@item T1
-There is a trace experiment running.
+
+@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, in bytes.
+
+@item tfree:@var{n}
+The number of bytes still unused in the buffer.
+
 @end table
 
 @item qTV:@var{var}
@@ -31147,6 +31229,10 @@ in a packet; it is not an error to return fewer than were asked for.
 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 01d558c..024b629 100644 (file)
@@ -9659,6 +9659,18 @@ remote_core_of_thread (struct target_ops *ops, ptid_t ptid)
 }
 
 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";
@@ -9736,6 +9748,7 @@ Specify the serial device it is connected to\n\
   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 f253ee0..bd5711f 100644 (file)
@@ -659,6 +659,7 @@ update_current_target (void)
       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.  */
@@ -848,7 +849,10 @@ update_current_target (void)
            tcomplain);
   de_fault (to_set_disconnected_tracing,
            (void (*) (int))
-           tcomplain);
+           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 7fd9bad..2b21f0f 100644 (file)
@@ -664,6 +664,7 @@ struct target_ops
     /* 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:
@@ -1359,6 +1360,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
 #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 8c60bdc..6dd14d5 100644 (file)
@@ -1,3 +1,8 @@
+2010-03-18  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.trace/circ.exp: Test circular-trace-buffer.
+       * gdb.trace/tfile.exp: Update tstatus test.
+
 2010-03-18  Joel Brobecker  <brobecker@adacore.com>
 
        * gdb.dwarf2/dw2-anonymous-func.S: New file.
index d18e7eb..bb3dcd3 100644 (file)
@@ -197,6 +197,15 @@ gdb_load $binfile
 if [target_info exists gdb_stub] {
     gdb_step_for_stub;
 }
+
+gdb_test "set circular-trace-buffer on" "" "set circular-trace-buffer on"
+
+gdb_test "show circular-trace-buffer" "Target's use of circular trace buffer is on." "show circular-trace-buffer (on)"
+
+gdb_test "set circular-trace-buffer off" "" "set circular-trace-buffer off"
+
+gdb_test "show circular-trace-buffer" "Target's use of circular trace buffer is off." "show circular-trace-buffer (off)"
+
 # Body of test encased in a proc so we can return prematurely.
 if { ![gdb_trace_circular_tests] } then {
     # Set trace buffer attributes back to normal
index 398b5ef..f1d86df 100644 (file)
@@ -78,8 +78,8 @@ gdb_test "tfind" "Target failed to find requested trace frame." \
 gdb_test "tstatus" \
     "Using a trace file.*
 Trace stopped by a tstop command.*
-Collected 1 trace frames.*
-Trace buffer has 256 bytes free.*
+Collected 1 trace frame.*
+Trace buffer has 256 bytes of 4096 bytes free \\(93% full\\).*
 Looking at trace frame 0, tracepoint .*" \
     "tstatus on trace file"
 
index b621334..8af3a9b 100644 (file)
@@ -153,6 +153,11 @@ char *default_collect = "";
 
 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);
@@ -1579,6 +1584,9 @@ trace_start_command (char *args, int from_tty)
   
   /* 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 ();
@@ -1668,16 +1676,34 @@ trace_status_command (char *args, int from_tty)
        }
     }
 
-  if (ts->traceframe_count >= 0)
+  if (ts->traceframes_created >= 0
+      && ts->traceframe_count != ts->traceframes_created)
+    {
+      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)
+  if (ts->buffer_free >= 0)
     {
-      printf_filtered (_("Trace buffer has %llu bytes free.\n"),
-                      ts->buffer_free);
+      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.  */
@@ -2438,10 +2464,18 @@ trace_save_command (char *args, int from_tty)
   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",
+  fprintf (fp, "status %c;%s:%x",
           (ts->running ? '1' : '0'),
-          stop_reason_names[ts->stop_reason], ts->stopping_tracepoint,
-          ts->traceframe_count, ts->buffer_free);
+          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
@@ -2546,6 +2580,13 @@ set_disconnected_tracing (char *args, int from_tty,
   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
@@ -3059,6 +3100,11 @@ parse_trace_status (char *line, struct trace_status *ts)
   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, ':');
@@ -3086,16 +3132,26 @@ Status line: '%s'\n"), p, line);
          p = unpack_varlen_hex (++p1, &val);
          ts->stop_reason = tstop_command;
        }
-      if (strncmp (p, "tframes", p1 - p) == 0)
+      else if (strncmp (p, "tframes", p1 - p) == 0)
        {
          p = unpack_varlen_hex (++p1, &val);
          ts->traceframe_count = val;
        }
-      if (strncmp (p, "tfree", p1 - p) == 0)
+      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.  */
@@ -3819,6 +3875,18 @@ trace data collected in the meantime."),
                           &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 c273f25..1ae5c6c 100644 (file)
@@ -95,11 +95,21 @@ struct trace_status
 
   int stopping_tracepoint;
 
+  /* Number of traceframes currently in the buffer.  */
+
   int traceframe_count;
 
-  unsigned long long buffer_size;
+  /* 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.  */
 
-  unsigned long long buffer_free;
+  int buffer_free;
 };
 
 struct trace_status *current_trace_status (void);