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 <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2024-08-20 17:38:55 +02:00
parent adc5153b5d
commit 5553ce0833

View File

@@ -37,11 +37,15 @@
#include <numeric>
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<QString, OutputFormat> &c) { return val + c.first.size(); });
if (totalQueuedSize > 5 * chunkSize) {
if (totalQueuedSize > 5 * d->chunkSize) {
d->flushRequested = true;
return;
}