aboutsummaryrefslogtreecommitdiff
path: root/gdb/cli-out.c
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2022-10-24 14:05:06 -0400
committerAaron Merey <amerey@redhat.com>2022-11-10 12:01:18 -0500
commit27859c6b9d73a8ae1b51c5c40fc2b3aefd2228a0 (patch)
treeae917c80fce78e048cbbd357f68ac2e9d2a61434 /gdb/cli-out.c
parentf71e3f86e83c9c22e3d86112b5ddb61919390a1a (diff)
downloadgdb-27859c6b9d73a8ae1b51c5c40fc2b3aefd2228a0.zip
gdb-27859c6b9d73a8ae1b51c5c40fc2b3aefd2228a0.tar.gz
gdb-27859c6b9d73a8ae1b51c5c40fc2b3aefd2228a0.tar.bz2
gdb/debuginfod: Improve progress updates
If the download size is known, a progress bar is displayed along with the percentage of completion and the total download size. Downloading separate debug info for /lib/libxyz.so [############ ] 25% (10.01 M) If the download size is not known, a progress indicator is displayed with a ticker ("###") that moves across the screen at a rate of 1 tick every 0.5 seconds. Downloading separate debug info for /lib/libxyz.so [ ### ] If the output stream is not a tty, batch mode is enabled, the screen is too narrow or width has been set to 'unlimited', then only a static description of the download is printed. No bar or ticker is displayed. Downloading separate debug info for /lib/libxyz.so... In any case, if the size of the download is known at the time the description is printed then it will be included in the description. Downloading 10.01 MB separate debug info for /lib/libxyz.so...
Diffstat (limited to 'gdb/cli-out.c')
-rw-r--r--gdb/cli-out.c189
1 files changed, 121 insertions, 68 deletions
diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index fdbed6f..9c2f018 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -26,6 +26,7 @@
#include "completer.h"
#include "readline/readline.h"
#include "cli/cli-style.h"
+#include "top.h"
/* These are the CLI output functions */
@@ -262,105 +263,157 @@ 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:
- <>
+/* Initialize a progress update to be displayed with
+ cli_ui_out::do_progress_notify. */
+
+void
+cli_ui_out::do_progress_start ()
+{
+ m_progress_info.emplace_back ();
+}
+
+#define MIN_CHARS_PER_LINE 50
+#define MAX_CHARS_PER_LINE 4096
+
+/* Print a progress update. MSG is a string to be printed on the line above
+ the progress bar. TOTAL is the size of the download whose progress is
+ being displayed. UNIT should be the unit of TOTAL (ex. "K"). If HOWMUCH
+ is between 0.0 and 1.0, a progress bar is displayed indicating the percentage
+ of completion and the download size. If HOWMUCH is negative, a progress
+ indicator will tick across the screen. If the output stream is not a tty
+ then only MSG is printed.
+
+ - printed for tty, HOWMUCH between 0.0 and 1.0:
+ <MSG
+ [######### ] HOWMUCH*100% (TOTAL UNIT)\r>
+ - printed for tty, HOWMUCH < 0.0:
+ <MSG
+ [ ### ]\r>
- printed for not-a-tty:
- <NAME...
- >
+ <MSG...\n>
*/
void
-cli_ui_out::do_progress_start (const std::string &name, bool should_print)
+cli_ui_out::do_progress_notify (const std::string &msg,
+ const char *unit,
+ double howmuch, double total)
{
+ int chars_per_line = get_chars_per_line ();
struct ui_file *stream = m_streams.back ();
- cli_progress_info meter;
+ cli_progress_info &info (m_progress_info.back ());
+
+ if (chars_per_line > MAX_CHARS_PER_LINE)
+ chars_per_line = MAX_CHARS_PER_LINE;
+
+ if (info.state == progress_update::START)
+ {
+ if (stream->isatty ()
+ && current_ui->input_interactive_p ()
+ && chars_per_line >= MIN_CHARS_PER_LINE)
+ {
+ gdb_printf (stream, "%s\n", msg.c_str ());
+ info.state = progress_update::BAR;
+ }
+ else
+ {
+ gdb_printf (stream, "%s...\n", msg.c_str ());
+ info.state = progress_update::WORKING;
+ }
+ }
+
+ if (info.state != progress_update::BAR
+ || chars_per_line < MIN_CHARS_PER_LINE)
+ return;
- meter.last_value = 0;
- meter.name = name;
- if (!stream->isatty ())
+ if (total > 0 && howmuch >= 0 && howmuch <= 1.0)
{
- gdb_printf (stream, "%s...", meter.name.c_str ());
+ std::string progress = string_printf (" %3.f%% (%.2f %s)",
+ howmuch * 100, total,
+ unit);
+ int width = chars_per_line - progress.size () - 4;
+ int max = width * howmuch;
+
+ std::string display = "\r[";
+
+ for (int i = 0; i < width; ++i)
+ if (i < max)
+ display += "#";
+ else
+ display += " ";
+
+ display += "]" + progress;
+ gdb_printf (stream, "%s", display.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;
+ using namespace std::chrono;
+ milliseconds diff = duration_cast<milliseconds>
+ (steady_clock::now () - info.last_update);
+
+ /* Advance the progress indicator at a rate of 1 tick every
+ every 0.5 seconds. */
+ if (diff.count () >= 500)
+ {
+ int width = chars_per_line - 4;
+
+ gdb_printf (stream, "\r[");
+ for (int i = 0; i < width; ++i)
+ {
+ if (i == info.pos % width
+ || i == (info.pos + 1) % width
+ || i == (info.pos + 2) % width)
+ gdb_printf (stream, "#");
+ else
+ gdb_printf (stream, " ");
+ }
+
+ gdb_printf (stream, "]");
+ gdb_flush (stream);
+ info.last_update = steady_clock::now ();
+ info.pos++;
+ }
}
- m_meters.push_back (std::move (meter));
+ return;
}
+/* Clear the current line of the most recent progress update. Overwrites
+ the current line with whitespace. */
+
void
-cli_ui_out::do_progress_notify (double howmuch)
+cli_ui_out::clear_current_line ()
{
struct ui_file *stream = m_streams.back ();
- cli_progress_info &meter (m_meters.back ());
+ int chars_per_line = get_chars_per_line ();
- if (meter.printing == NO_PRINT)
+ if (!stream->isatty ()
+ || !current_ui->input_interactive_p ()
+ || chars_per_line < MIN_CHARS_PER_LINE)
return;
- if (meter.printing == START)
- {
- gdb_printf (stream, "%s\n", meter.name.c_str ());
- gdb_flush (stream);
- meter.printing = WORKING;
- }
-
- if (meter.printing == WORKING && howmuch >= 1.0)
- return;
+ if (chars_per_line > MAX_CHARS_PER_LINE)
+ chars_per_line = MAX_CHARS_PER_LINE;
- if (!stream->isatty ())
- return;
+ gdb_printf (stream, "\r");
+ for (int i = 0; i < chars_per_line; ++i)
+ gdb_printf (stream, " ");
+ gdb_printf (stream, "\r");
- 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;
- gdb_printf (stream, "\r[");
- for (i = 0; i < width; ++i)
- gdb_printf (stream, i < max ? "#" : " ");
- gdb_printf (stream, "]");
- gdb_flush (stream);
- meter.printing = PROGRESS;
- }
+ gdb_flush (stream);
}
+/* Remove the most recent progress update from the progress_info stack
+ and overwrite the current line with whitespace. */
+
void
cli_ui_out::do_progress_end ()
{
struct ui_file *stream = m_streams.back ();
- cli_progress_info &meter = m_meters.back ();
-
- if (!stream->isatty ())
- {
- gdb_printf (stream, "\n");
- gdb_flush (stream);
- }
- else if (meter.printing == PROGRESS)
- {
- int i;
- int width = get_chars_per_line () - 3;
-
- gdb_printf (stream, "\r");
- for (i = 0; i < width + 2; ++i)
- gdb_printf (stream, " ");
- gdb_printf (stream, "\r");
- gdb_flush (stream);
- }
+ m_progress_info.pop_back ();
- m_meters.pop_back ();
+ if (stream->isatty ())
+ clear_current_line ();
}
/* local functions */