From 5553ce08332ee254e469ec622533447871a49c28 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Aug 2024 17:38:55 +0200 Subject: [PATCH] Core: Adapt output window chunk size and queue timer dynamically If we notice that our formatter takes longer to handle an incoming chunk of output than the amount of time we wait until we handle the next one, then we lower the chunk size and increase the interval. This way, we ensure responsiveness in the presence of excessive output. Task-number: QTCREATORBUG-30135 Change-Id: I1d1e31a7c6f26b50bdc048322e0f7987ddd7b317 Reviewed-by: David Schulz --- src/plugins/coreplugin/outputwindow.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index 1d2f61c0e44..681b8496814 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -37,11 +37,15 @@ #include -const int chunkSize = 10000; - using namespace Utils; using namespace std::chrono_literals; +const int defaultChunkSize = 10000; +const int minChunkSize = 1000; + +const auto defaultInterval = 10ms; +const auto maxInterval = 1000ms; + namespace Core { namespace Internal { @@ -70,6 +74,7 @@ public: QTextCursor cursor; QString filterText; int lastFilteredBlockNumber = -1; + int chunkSize = defaultChunkSize; QPalette originalPalette; OutputWindow::FilterModeFlags filterMode = OutputWindow::FilterModeFlag::Default; int beforeContext = 0; @@ -97,7 +102,7 @@ OutputWindow::OutputWindow(Context context, const Key &settingsKey, QWidget *par d->formatter.setPlainTextEdit(this); d->queueTimer.setSingleShot(true); - d->queueTimer.setInterval(10ms); + d->queueTimer.setInterval(defaultInterval); connect(&d->queueTimer, &QTimer::timeout, this, &OutputWindow::handleNextOutputChunk); d->settingsKey = settingsKey; @@ -492,7 +497,7 @@ void OutputWindow::handleNextOutputChunk() // We want to break off the chunks along line breaks, if possible. // Otherwise we can get ugly temporary artifacts e.g. for ANSI escape codes. - int actualChunkSize = std::min(chunkSize, int(chunk.first.size())); + int actualChunkSize = std::min(d->chunkSize, int(chunk.first.size())); const int minEndPos = std::max(0, actualChunkSize - 1000); for (int i = actualChunkSize - 1; i >= minEndPos; --i) { if (chunk.first.at(i) == '\n') { @@ -544,7 +549,13 @@ void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format) } } + QElapsedTimer formatterTimer; + formatterTimer.start(); d->formatter.appendMessage(out, format); + if (formatterTimer.elapsed() > d->queueTimer.interval()) { + d->queueTimer.setInterval(std::min(maxInterval, d->queueTimer.intervalAsDuration() * 2)); + d->chunkSize = std::max(minChunkSize, d->chunkSize / 2); + } if (d->scrollToBottom) { if (d->lastMessage.elapsed() < 5) { @@ -659,7 +670,7 @@ void OutputWindow::flush() { const int totalQueuedSize = std::accumulate(d->queuedOutput.cbegin(), d->queuedOutput.cend(), 0, [](int val, const QPair &c) { return val + c.first.size(); }); - if (totalQueuedSize > 5 * chunkSize) { + if (totalQueuedSize > 5 * d->chunkSize) { d->flushRequested = true; return; }