From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 8D1cG7ix01+HawAAWB0awg (envelope-from ) for ; Fri, 11 Dec 2020 12:51:52 -0500 Received: by simark.ca (Postfix, from userid 112) id 6CC451F0A9; Fri, 11 Dec 2020 12:51:52 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 37B6D1E590 for ; Fri, 11 Dec 2020 12:51:51 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AA16F3857817; Fri, 11 Dec 2020 17:51:50 +0000 (GMT) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by sourceware.org (Postfix) with ESMTPS id 757ED3857817 for ; Fri, 11 Dec 2020 17:51:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 757ED3857817 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tdevries@suse.de X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 7DE87AE4A; Fri, 11 Dec 2020 17:51:46 +0000 (UTC) Subject: [gdb/cli] Add a progress meter To: Tom Tromey References: <6ad82f30-0ca3-8b19-2907-d71f0dfecafe@suse.cz> <2c28a403-a169-0dc3-9b64-58484237c8c2@suse.cz> <72061fbb-b480-04ce-ef4a-fe13a7266885@suse.de> <87a6ulmppr.fsf@tromey.com> From: Tom de Vries Message-ID: <5506b198-c504-0046-0559-bcc24538d31c@suse.de> Date: Fri, 11 Dec 2020 18:51:45 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.5.0 MIME-Version: 1.0 In-Reply-To: <87a6ulmppr.fsf@tromey.com> Content-Type: multipart/mixed; boundary="------------09DA5E95E3FD5CC2BBB4ED40" Content-Language: en-US X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: gdb-patches@sourceware.org Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" This is a multi-part message in MIME format. --------------09DA5E95E3FD5CC2BBB4ED40 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit [ Re: [PATCH] gdb: print size of downloaded debuginfod binary ] On 12/10/20 8:21 PM, Tom Tromey wrote: > Tom> This updated patch fixes both problems, the latter by printing the % > Tom> progress on its own line (which is cleared by a final '\r' after > Tom> reaching 100%, in order not to waste lines on this). > > A long time ago I had patches to show a progress bar when reading DWARF. > > https://sourceware.org/pipermail/gdb-patches/2017-April/139882.html > > Maybe this could be resurrected. > I've occasionally thought of adding this to the TUI as well, say briefly > overwriting the status bar with a progress meter. I've taken a look, and think that this code is more in line with gdb cli setup, so I've reimplemented on top of this. Here is the first patch, adding the progress meter infrastructure factored out from your patch. Thanks, - Tom --------------09DA5E95E3FD5CC2BBB4ED40 Content-Type: text/x-patch; charset=UTF-8; name="0001-gdb-cli-Add-a-progress-meter.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="0001-gdb-cli-Add-a-progress-meter.patch" [gdb/cli] Add a progress meter This patch adds a progress bar. It's not used anywhere yet. gdb/ChangeLog: 2020-12-11 Tom Tromey Tom de Vries * 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) : New methods. : New. : 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 | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/cli-out.h | 29 ++++++++++++++++++++ gdb/mi/mi-out.h | 12 ++++++++ gdb/ui-out.h | 36 ++++++++++++++++++++++++ gdb/utils.c | 8 ++++++ gdb/utils.h | 4 +++ 6 files changed, 174 insertions(+) diff --git a/gdb/cli-out.c b/gdb/cli-out.c index e47272ad87..5d07426b73 100644 --- a/gdb/cli-out.c +++ b/gdb/cli-out.c @@ -265,6 +265,91 @@ cli_ui_out::do_redirect (ui_file *outstream) m_streams.pop_back (); } +void +cli_ui_out::do_progress_start (const std::string &name, int 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 notify 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 (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 (stream->isatty ()) + { + int i, max; + int width = get_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); + } +} + +void +cli_ui_out::do_progress_end () +{ + struct ui_file *stream = m_streams.back (); + cli_progress_info &meter = m_meters.back (); + + if (meter.printing != NO_PRINT) + { + if (stream->isatty ()) + { + 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); + } + else + { + fprintf_unfiltered (stream, "done.\n"); + gdb_flush (stream); + } + } + + m_meters.pop_back (); +} + /* local functions */ void diff --git a/gdb/cli-out.h b/gdb/cli-out.h index 84e957ca89..0c45b77d07 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 &, int) override; + virtual void do_progress_notify (double) override; + virtual void do_progress_end () override; + bool suppress_output () { return m_suppress_output; } @@ -80,6 +84,31 @@ class cli_ui_out : public ui_out std::vector 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, + /* 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 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..4be0decd14 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 &, int) 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..9ae4eeb83a 100644 --- a/gdb/ui-out.h +++ b/gdb/ui-out.h @@ -275,6 +275,38 @@ 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: + progress_meter (struct ui_out *uiout, const std::string &name, + int 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 +341,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 &, int) = 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..b1d1694584 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 (void) +{ + 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 diff --git a/gdb/utils.h b/gdb/utils.h index a8c65ed817..5ae97b7469 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 (void); + extern bool pagination_enabled; extern struct ui_file **current_ui_gdb_stdout_ptr (void); --------------09DA5E95E3FD5CC2BBB4ED40--