Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: Tom Tromey <tom@tromey.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [gdb/cli] Add a progress meter
Date: Sat, 12 Dec 2020 17:35:24 +0100	[thread overview]
Message-ID: <2673dab0-5e37-e7dc-a6f8-bb764aa22d6a@suse.de> (raw)
In-Reply-To: <87k0togndu.fsf@tromey.com>

[-- Attachment #1: Type: text/plain, Size: 2172 bytes --]

On 12/11/20 8:21 PM, Tom Tromey wrote:
>>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:
> 
> Tom> I've taken a look, and think that this code is more in line with gdb cli
> Tom> setup, so I've reimplemented on top of this.
> 
> Tom> Here is the first patch, adding the progress meter infrastructure
> Tom> factored out from your patch.
> 
> Not sure if I ought to review a patch that I largely wrote, but I did
> find some things I think should be done differently nowadays.
> 
> Tom> +void
> Tom> +cli_ui_out::do_progress_start (const std::string &name, int should_print)
> 
> should_print should probably be a bool, throughout this patch.
> 

Done.

> Tom> +      /* Don't actually emit anything until the first call notify us
> 
> I think s/notify/notifies/
> 

Done.

> Tom> +  if (!stream->isatty ())
> Tom> +    {
> Tom> +      fprintf_unfiltered (stream, "%s...", meter.name.c_str ());
> 
> This is probably fine but I suppose the meaning of "should_print" ought
> to be described somewhere,

Done.

> since otherwise this could seem like a bug --
> it is printing something even when should_print==false.
> 
> Tom> +  m_meters.push_back (meter);
> 
> std::move(meter) would be more efficient here, since it would avoid
> another string copy.
> 

Done.

> Tom> +    progress_meter (struct ui_out *uiout, const std::string &name,
> Tom> +		    int should_print)
> Tom> +      : m_uiout (uiout)
> 
> Here's probably where should_print should be documented.
> 
> Tom> +get_chars_per_line (void)
> 
> Just "()", not "(void)", now.
> 
> Tom> +++ b/gdb/utils.h
> Tom> @@ -364,6 +364,10 @@ extern void wrap_here (const char *);
>  
> Tom>  extern void reinitialize_more_filter (void);
>  
> Tom> +/* Return the number of characters in a line.  */
> Tom> +
> Tom> +extern int get_chars_per_line (void);
> 
> Here too.

Done.

I've also fixed the first-progress-call-has-howmuch=1.0 problem
mentioned in the original review conversation with Pedro, by adding a
new enum meter_state element PROGRESS.

I've also fixed the problem that when f.i. run with -batch,
chars_per_line is zero. The previous version of the patch was printing
"[]" in that case.

Thanks,
- Tom


[-- Attachment #2: 0010-gdb-cli-Add-a-progress-meter.patch --]
[-- Type: text/x-patch, Size: 9100 bytes --]

[gdb/cli] Add a progress meter

Add a progress meter.  It's not used anywhere yet.

gdb/ChangeLog:

2020-12-11  Tom Tromey  <tom@tromey.com>
	    Tom de Vries  <tdevries@suse.de>

	* utils.h (get_chars_per_line): Declare.
	* utils.c (get_chars_per_line): New function.
	(fputs_maybe_filtered): Handle '\r'.
	* ui-out.h (ui_out::progress_meter): New class.
	(ui_out::progress, ui_out::do_progress_start)
	(ui_out::do_progress_notify, ui_out::do_progress_end): New
	methods.
	* ui-out.c (do_progress_end)
	(make_cleanup_ui_out_progress_begin_end, ui_out_progress): New
	functions.
	* mi/mi-out.h (mi_ui_out::do_progress_start)
	(mi_ui_out::do_progress_notify, mi_ui_out::do_progress_end): New
	methods.
	* cli-out.h (struct cli_ui_out) <do_progress_start,
	do_progress_notify, do_progress_end>: New methods.
	<enum meter_stat, struct cli_progress_info>: New.
	<m_meters>: New member.
	* cli-out.c (cli_ui_out::do_progress_start)
	(cli_ui_out::do_progress_notify, cli_ui_out::do_progress_end): New
	methods.

---
 gdb/cli-out.c   | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/cli-out.h   |  31 +++++++++++++++++
 gdb/mi/mi-out.h |  12 +++++++
 gdb/ui-out.h    |  37 +++++++++++++++++++++
 gdb/utils.c     |  14 ++++++++
 gdb/utils.h     |   4 +++
 6 files changed, 199 insertions(+)

diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index e47272ad87..7722ecc4fe 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -265,6 +265,107 @@ cli_ui_out::do_redirect (ui_file *outstream)
     m_streams.pop_back ();
 }
 
+/* The cli_ui_out::do_progress_* functions result in the following:
+   - printed for tty, SHOULD_PRINT == true:
+     <NAME
+      [#####                      ]\r>
+   - printed for tty, SHOULD_PRINT == false:
+     <>
+   - printed for not-a-tty:
+     <NAME...done.
+     >
+*/
+
+void
+cli_ui_out::do_progress_start (const std::string &name, bool should_print)
+{
+  struct ui_file *stream = m_streams.back ();
+  cli_progress_info meter;
+
+  meter.last_value = 0;
+  meter.name = name;
+  if (!stream->isatty ())
+    {
+      fprintf_unfiltered (stream, "%s...", meter.name.c_str ());
+      gdb_flush (stream);
+      meter.printing = WORKING;
+    }
+  else
+    {
+      /* Don't actually emit anything until the first call notifies us
+	 of progress.  This makes it so a second progress message can
+	 be started before the first one has been notified, without
+	 messy output.  */
+      meter.printing = should_print ? START : NO_PRINT;
+    }
+
+  m_meters.push_back (std::move (meter));
+}
+
+void
+cli_ui_out::do_progress_notify (double howmuch)
+{
+  struct ui_file *stream = m_streams.back ();
+  cli_progress_info &meter (m_meters.back ());
+
+  if (meter.printing == NO_PRINT)
+    return;
+
+  if (meter.printing == START)
+    {
+      fprintf_unfiltered (stream, "%s\n", meter.name.c_str ());
+      gdb_flush (stream);
+      meter.printing = WORKING;
+    }
+
+  if (meter.printing == WORKING && howmuch >= 1.0)
+    return;
+
+  if (!stream->isatty ())
+    return;
+
+  int chars_per_line = get_chars_per_line ();
+  if (chars_per_line > 0)
+    {
+      int i, max;
+      int width = chars_per_line - 3;
+
+      max = width * howmuch;
+      fprintf_unfiltered (stream, "\r[");
+      for (i = 0; i < width; ++i)
+	fprintf_unfiltered (stream, i < max ? "#" : " ");
+      fprintf_unfiltered (stream, "]");
+      gdb_flush (stream);
+      meter.printing = PROGRESS;
+    }
+}
+
+void
+cli_ui_out::do_progress_end ()
+{
+  struct ui_file *stream = m_streams.back ();
+  cli_progress_info &meter = m_meters.back ();
+
+  if (!stream->isatty ())
+    {
+      fprintf_unfiltered (stream, "done.\n");
+      gdb_flush (stream);
+    }
+  else if (meter.printing == PROGRESS)
+    {
+      int i;
+      int width = get_chars_per_line () - 3;
+
+      fprintf_unfiltered (stream, "\r");
+      for (i = 0; i < width + 2; ++i)
+	fprintf_unfiltered (stream, " ");
+      fprintf_unfiltered (stream, "\r");
+      gdb_flush (stream);
+    }
+
+  m_meters.pop_back ();
+}
+
 /* local functions */
 
 void
diff --git a/gdb/cli-out.h b/gdb/cli-out.h
index 84e957ca89..5f55554fdb 100644
--- a/gdb/cli-out.h
+++ b/gdb/cli-out.h
@@ -71,6 +71,10 @@ class cli_ui_out : public ui_out
   virtual void do_flush () override;
   virtual void do_redirect (struct ui_file *outstream) override;
 
+  virtual void do_progress_start (const std::string &, bool) override;
+  virtual void do_progress_notify (double) override;
+  virtual void do_progress_end () override;
+
   bool suppress_output ()
   { return m_suppress_output; }
 
@@ -80,6 +84,33 @@ class cli_ui_out : public ui_out
 
   std::vector<ui_file *> m_streams;
   bool m_suppress_output;
+
+  /* Represents the printing state of a progress meter.  */
+  enum meter_state
+  {
+    /* Printing will start with the next output.  */
+    START,
+    /* Printing has already started.  */
+    WORKING,
+    /* Progress printing has already started.  */
+    PROGRESS,
+    /* Printing should not be done.  */
+    NO_PRINT
+  };
+
+  /* The state of a recent progress meter.  */
+  struct cli_progress_info
+  {
+    /* The current state.  */
+    enum meter_state printing;
+    /* The name to print.  */
+    std::string name;
+    /* The last notification value.  */
+    double last_value;
+  };
+
+  /* Stack of progress meters.  */
+  std::vector<cli_progress_info> m_meters;
 };
 
 extern cli_ui_out *cli_out_new (struct ui_file *stream);
diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h
index de4b3e01a4..da8f4e6457 100644
--- a/gdb/mi/mi-out.h
+++ b/gdb/mi/mi-out.h
@@ -83,6 +83,18 @@ class mi_ui_out : public ui_out
   virtual bool do_is_mi_like_p () const override
   { return true; }
 
+  virtual void do_progress_start (const std::string &, bool) override
+  {
+  }
+
+  virtual void do_progress_notify (double) override
+  {
+  }
+
+  virtual void do_progress_end () override
+  {
+  }
+
 private:
 
   void field_separator ();
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 9fc60614d6..dfd9679e4c 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -275,6 +275,39 @@ class ui_out
      escapes.  */
   virtual bool can_emit_style_escape () const = 0;
 
+  /* An object that starts and finishes a progress meter.  */
+  class progress_meter
+  {
+  public:
+    /* SHOULD_PRINT indicates whether something should be printed for a tty.  */
+    progress_meter (struct ui_out *uiout, const std::string &name,
+		    bool should_print)
+      : m_uiout (uiout)
+    {
+      m_uiout->do_progress_start (name, should_print);
+    }
+
+    ~progress_meter ()
+    {
+      m_uiout->do_progress_notify (1.0);
+      m_uiout->do_progress_end ();
+    }
+
+    progress_meter (const progress_meter &) = delete;
+    progress_meter &operator= (const progress_meter &) = delete;
+
+  private:
+
+    struct ui_out *m_uiout;
+  };
+
+  /* Emit some progress corresponding to the most recently created
+     progress meter.  HOWMUCH may range from 0.0 to 1.0.  */
+  void progress (double howmuch)
+  {
+    do_progress_notify (howmuch);
+  }
+
  protected:
 
   virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid)
@@ -309,6 +342,10 @@ class ui_out
   virtual void do_flush () = 0;
   virtual void do_redirect (struct ui_file *outstream) = 0;
 
+  virtual void do_progress_start (const std::string &, bool) = 0;
+  virtual void do_progress_notify (double) = 0;
+  virtual void do_progress_end () = 0;
+
   /* Set as not MI-like by default.  It is overridden in subclasses if
      necessary.  */
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 3226656e2c..abcf6e256b 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1579,6 +1579,14 @@ gdb_flush (struct ui_file *stream)
   stream->flush ();
 }
 
+/* See utils.h.  */
+
+int
+get_chars_per_line ()
+{
+  return chars_per_line;
+}
+
 /* Indicate that if the next sequence of characters overflows the line,
    a newline should be inserted here rather than when it hits the end.
    If INDENT is non-null, it is a string to be printed to indent the
@@ -1769,6 +1777,12 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
 		 don't increment chars_printed here.  */
 	      lineptr += skip_bytes;
 	    }
+	  else if (*lineptr == '\r')
+	    {
+	      wrap_buffer.push_back (*lineptr);
+	      chars_printed = 0;
+	      lineptr++;
+	    }
 	  else
 	    {
 	      wrap_buffer.push_back (*lineptr);
diff --git a/gdb/utils.h b/gdb/utils.h
index a8c65ed817..e87ce11323 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -364,6 +364,10 @@ extern void wrap_here (const char *);
 
 extern void reinitialize_more_filter (void);
 
+/* Return the number of characters in a line.  */
+
+extern int get_chars_per_line ();
+
 extern bool pagination_enabled;
 
 extern struct ui_file **current_ui_gdb_stdout_ptr (void);

  reply	other threads:[~2020-12-12 16:35 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-07 11:43 [PATCH] gdb: print size of downloaded debuginfod binary Martin Liška
2020-12-07 17:07 ` Simon Marchi via Gdb-patches
2020-12-08 10:16   ` Martin Liška
2020-12-08 14:28     ` Simon Marchi via Gdb-patches
2020-12-09 10:51       ` Martin Liška
2020-12-09 23:26         ` Tom de Vries
2020-12-10  8:26           ` Martin Liška
2020-12-10 19:21           ` Tom Tromey
2020-12-11 17:51             ` [gdb/cli] Add a progress meter Tom de Vries
2020-12-11 17:54               ` [PATCH] gdb: print size of downloaded debuginfod binary Tom de Vries
2020-12-11 19:23                 ` Tom Tromey
2020-12-12 16:43                   ` Tom de Vries
2020-12-15 20:29                     ` Tom Tromey
2020-12-11 19:21               ` [gdb/cli] Add a progress meter Tom Tromey
2020-12-12 16:35                 ` Tom de Vries [this message]
2020-12-15 20:28                   ` Tom Tromey
2020-12-09 20:16   ` [PATCH] gdb: print size of downloaded debuginfod binary Tom Tromey

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=2673dab0-5e37-e7dc-a6f8-bb764aa22d6a@suse.de \
    --to=tdevries@suse.de \
    --cc=gdb-patches@sourceware.org \
    --cc=tom@tromey.com \
    /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