[llvm] [lit] Add an option to lit which ratelimits progressbar output. (PR #186479)

Nick Begg via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 04:12:38 PDT 2026


https://github.com/neek78 updated https://github.com/llvm/llvm-project/pull/186479

>From f61a635281640348fde22e154ab531abbc493c87 Mon Sep 17 00:00:00 2001
From: Nick Begg <nick at stunttruck.net>
Date: Fri, 13 Mar 2026 18:30:00 +0100
Subject: [PATCH 1/4] [lit] Add an option to lit which ratelimits progressbar
 output.

Add a new option --min-output-interval, which ratelimits updates to
the progress bar. Only applies when using the full curses progress
bar, not the simplified one, nor does it affect the log message output.
---
 llvm/utils/lit/lit/ProgressBar.py  | 18 +++++++++++++++++-
 llvm/utils/lit/lit/cl_arguments.py | 23 +++++++++++++++++++++++
 llvm/utils/lit/lit/display.py      |  4 +++-
 3 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/llvm/utils/lit/lit/ProgressBar.py b/llvm/utils/lit/lit/ProgressBar.py
index 382b8f2e52540..2af916866427d 100644
--- a/llvm/utils/lit/lit/ProgressBar.py
+++ b/llvm/utils/lit/lit/ProgressBar.py
@@ -237,7 +237,7 @@ class ProgressBar:
     BAR = "%s${%s}[${BOLD}%s%s${NORMAL}${%s}]${NORMAL}%s"
     HEADER = "${BOLD}${CYAN}%s${NORMAL}\n\n"
 
-    def __init__(self, term, header, useETA=True):
+    def __init__(self, term, header, useETA=True, minOutputInterval=None):
         self.term = term
         if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
             raise ValueError(
@@ -261,7 +261,23 @@ def __init__(self, term, header, useETA=True):
             self.startTime = time.time()
         # self.update(0, '')
 
+        self.lastUpdateTime = 0
+        self.minOutputInterval = minOutputInterval
+        # the checks preceeding us should prevent getting here if output is redirected
+        # - we don't want to rate limit (ie drop) output to a file
+        assert sys.stdout.isatty()
+
     def update(self, percent, message):
+        # ratelimit updates
+        if self.minOutputInterval is not None:
+            now = time.time()
+            if now - self.lastUpdateTime < self.minOutputInterval:
+                # ... too soon. Technically, this means we could 'starve'
+                # the output if the next update takes too long to come, but that
+                # doesn't seem to be an issue in practice
+                return
+            self.lastUpdateTime = now
+
         if self.cleared:
             sys.stdout.write(self.header)
             self.cleared = 0
diff --git a/llvm/utils/lit/lit/cl_arguments.py b/llvm/utils/lit/lit/cl_arguments.py
index 2fe2ed60aca70..fe3054fcb6065 100644
--- a/llvm/utils/lit/lit/cl_arguments.py
+++ b/llvm/utils/lit/lit/cl_arguments.py
@@ -235,6 +235,14 @@ def parse_args():
         help="Do not use curses based progress bar (default)",
         action="store_false",
     )
+    format_group.add_argument(
+        "--min-output-interval",
+        dest="minOutputInterval",
+        help="Limit updates to progressbar to at most once per INTERVAL, in seconds. Set to 0 to disable ratelimit (default 0.2 seconds).",
+        default=0.2,
+        metavar="INTERVAL",
+        type=_non_negative_float,
+    )
 
     # Note: this does not generate flags for user-defined result codes.
     success_codes = [c for c in lit.Test.ResultCode.all_codes() if not c.isFailure]
@@ -548,6 +556,21 @@ def _int(arg, kind, pred):
     return i
 
 
+def _non_negative_float(arg):
+    return _float(arg, "non-negative", lambda f: f >= 0.0)
+
+
+def _float(arg, kind, pred):
+    desc = "requires {} float, but found '{}'"
+    try:
+        f = float(arg)
+    except ValueError:
+        raise _error(desc, kind, arg)
+    if not pred(f):
+        raise _error(desc, kind, arg)
+    return f
+
+
 def _case_insensitive_regex(arg):
     import re
 
diff --git a/llvm/utils/lit/lit/display.py b/llvm/utils/lit/lit/display.py
index c6057fde39d59..278a82b555564 100644
--- a/llvm/utils/lit/lit/display.py
+++ b/llvm/utils/lit/lit/display.py
@@ -19,7 +19,9 @@ def create_display(opts, tests, total_tests, workers):
 
         try:
             tc = lit.ProgressBar.TerminalController()
-            progress_bar = lit.ProgressBar.ProgressBar(tc, header)
+            progress_bar = lit.ProgressBar.ProgressBar(
+                tc, header, minOutputInterval=opts.minOutputInterval
+            )
             header = None
         except ValueError:
             progress_bar = lit.ProgressBar.SimpleProgressBar("Testing: ")

>From c2ae459f3d753059ecc1d02ee5ef113c4a367ace Mon Sep 17 00:00:00 2001
From: Nick Begg <nick at stunttruck.net>
Date: Thu, 19 Mar 2026 13:40:53 +0100
Subject: [PATCH 2/4] fixup! [lit] Add an option to lit which ratelimits
 progressbar output.

---
 llvm/utils/lit/lit/ProgressBar.py  | 2 +-
 llvm/utils/lit/lit/cl_arguments.py | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/utils/lit/lit/ProgressBar.py b/llvm/utils/lit/lit/ProgressBar.py
index 2af916866427d..68e3e450e44b8 100644
--- a/llvm/utils/lit/lit/ProgressBar.py
+++ b/llvm/utils/lit/lit/ProgressBar.py
@@ -237,7 +237,7 @@ class ProgressBar:
     BAR = "%s${%s}[${BOLD}%s%s${NORMAL}${%s}]${NORMAL}%s"
     HEADER = "${BOLD}${CYAN}%s${NORMAL}\n\n"
 
-    def __init__(self, term, header, useETA=True, minOutputInterval=None):
+    def __init__(self, term, header, minOutputInterval, useETA=True):
         self.term = term
         if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
             raise ValueError(
diff --git a/llvm/utils/lit/lit/cl_arguments.py b/llvm/utils/lit/lit/cl_arguments.py
index fe3054fcb6065..5ed818fb93844 100644
--- a/llvm/utils/lit/lit/cl_arguments.py
+++ b/llvm/utils/lit/lit/cl_arguments.py
@@ -238,8 +238,8 @@ def parse_args():
     format_group.add_argument(
         "--min-output-interval",
         dest="minOutputInterval",
-        help="Limit updates to progressbar to at most once per INTERVAL, in seconds. Set to 0 to disable ratelimit (default 0.2 seconds).",
-        default=0.2,
+        help="Limit updates to progressbar to at most once per INTERVAL, in seconds. Set to 0 to disable ratelimit (default - no ratelimit).",
+        default=0.0,
         metavar="INTERVAL",
         type=_non_negative_float,
     )

>From 3ec996ff52ecda4dde42cfef58c844c713bce471 Mon Sep 17 00:00:00 2001
From: Nick Begg <nick at stunttruck.net>
Date: Tue, 31 Mar 2026 15:08:54 +0200
Subject: [PATCH 3/4] add --min-output-interval description to lit.rst

---
 llvm/docs/CommandGuide/lit.rst | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/docs/CommandGuide/lit.rst b/llvm/docs/CommandGuide/lit.rst
index bbeafd2b9234c..2e14f53d110cb 100644
--- a/llvm/docs/CommandGuide/lit.rst
+++ b/llvm/docs/CommandGuide/lit.rst
@@ -120,6 +120,11 @@ OUTPUT OPTIONS
 
  Do not use curses based progress bar.
 
+.. option:: --min-output-interval INTERVAL
+
+ Only output updates to the progress bar and status line at most once per
+ INTERVAL seconds. Has no effect if the curses based progress bar is not used.
+
 .. option:: --show-excluded
 
  Show excluded tests.

>From f86386afa07b44648fb018abcc4e270ad95a84cd Mon Sep 17 00:00:00 2001
From: Nick Begg <nick at stunttruck.net>
Date: Sat, 4 Apr 2026 13:12:28 +0200
Subject: [PATCH 4/4] Update llvm/utils/lit/lit/cl_arguments.py

Co-authored-by: Alexander Richardson <mail at alexrichardson.me>
---
 llvm/utils/lit/lit/cl_arguments.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/llvm/utils/lit/lit/cl_arguments.py b/llvm/utils/lit/lit/cl_arguments.py
index 5ed818fb93844..a98dc04816530 100644
--- a/llvm/utils/lit/lit/cl_arguments.py
+++ b/llvm/utils/lit/lit/cl_arguments.py
@@ -568,6 +568,13 @@ def _float(arg, kind, pred):
         raise _error(desc, kind, arg)
     if not pred(f):
         raise _error(desc, kind, arg)
+def _float(arg, kind, pred):
+    try:
+        f = float(arg)
+        if not pred(f):
+            raise ValueError()
+    except ValueError:
+        raise argparse.ArgumentTypeError(f"requires {kind} float, but found '{arg}'")
     return f
 
 



More information about the llvm-commits mailing list