Commit 0a916158 authored by Milian Wolff's avatar Milian Wolff
Browse files

prevent UI-lockup when adding lots of stdout lines to make output model

we now add batches of 50 lines and then return to the event loop,
continuing with the rest of the lines via a QueuedConnection

the unit test shows that (on my machine) the event loop is roughly
returning every 80ms. the test ensures that this time does not cross
the threshold of 200ms which is imo too much.

on a further note, it is interesting to see that optimizing the actual
adding of lines is not easily possible, the tons of regexp matching
is simply required... the only possible way would be to make the error
patterns configurable such that e.g. those for unused compilers or
unused toolchains are not queried.

BUG: 295361
parent 4cc0a033
......@@ -202,10 +202,22 @@ void MakeOutputModel::addLines( const QStringList& lines )
{
if( lines.isEmpty() )
return;
beginInsertRows( QModelIndex(), rowCount(), rowCount() + lines.count() - 1 );
foreach( const QString& line, lines )
{
lineBuffer << lines;
QMetaObject::invokeMethod(this, "addLineBatch", Qt::QueuedConnection);
}
void MakeOutputModel::addLineBatch()
{
// only add this many lines in one batch, then return to the event loop
// this prevents overly long UI lockup and is simple enough to implement
const int maxLines = 50;
const int linesInBatch = qMin(lineBuffer.count(), maxLines);
beginInsertRows( QModelIndex(), rowCount(), rowCount() + linesInBatch - 1);
for(int i = 0; i < linesInBatch; ++i) {
const QString line = lineBuffer.dequeue();
FilteredItem item( line );
bool matched = false;
......@@ -305,6 +317,10 @@ void MakeOutputModel::addLines( const QStringList& lines )
items << item;
}
endInsertRows();
if (!lineBuffer.isEmpty()) {
QMetaObject::invokeMethod(this, "addLineBatch", Qt::QueuedConnection);
}
}
void MakeOutputModel::addLine( const QString& l )
......
......@@ -29,6 +29,7 @@
#include <QLinkedList>
#include <QMap>
#include <QVector>
#include <QQueue>
class FilteredItem
{
......@@ -72,6 +73,10 @@ public:
void addLines( const QStringList& );
void addLine( const QString& );
private slots:
/// add batches of lines to prevent UI-lockup
void addLineBatch();
private:
KUrl urlForFile( const QString& ) const;
bool isValidIndex( const QModelIndex& ) const;
......@@ -84,6 +89,7 @@ private:
PositionMap positionInCurrentDirs;
KUrl buildDir;
QQueue<QString> lineBuffer;
};
Q_DECLARE_METATYPE( MakeOutputModel::OutputItemType )
......
......@@ -25,6 +25,8 @@
#include <QStringList>
#include <QTest>
#include <QSignalSpy>
#include <QDebug>
QTEST_MAIN(TestMakeOutputModel)
......@@ -35,6 +37,7 @@ TestMakeOutputModel::TestMakeOutputModel(QObject* parent): QObject(parent)
void TestMakeOutputModel::benchAddLines()
{
// see also: https://bugs.kde.org/show_bug.cgi?id=295361
MakeOutputModel model(KUrl("/tmp/build-foo"));
QStringList lines;
const int numLines = 1000;
......@@ -42,9 +45,28 @@ void TestMakeOutputModel::benchAddLines()
for(int i = 0; i < numLines; ++i) {
lines << (QString::number(i) + QString().fill('a', charsPerLine));
}
qRegisterMetaType<QModelIndex>("QModelIndex");
QSignalSpy spy(&model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)));
QElapsedTimer totalTime;
totalTime.start();
QBENCHMARK {
model.addLines(lines);
while(model.rowCount() != lines.count()) {
QCoreApplication::instance()->processEvents();
}
}
QVERIFY(model.rowCount() == lines.count());
const qint64 elapsed = totalTime.elapsed();
qDebug() << "ms elapsed to add lines: " << elapsed;
qDebug() << "total number of added lines: " << lines.count();
const double avgUiLockup = double(elapsed) / spy.count();
qDebug() << "average UI lockup in ms: " << avgUiLockup;
QVERIFY(avgUiLockup < 200);
}
#include "test_makeoutputmodel.moc"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment