Solved Lagging window/gui when using realtime table view
-
@Mr-Gisa said in Lagging window/gui when using realtime table view:
You think that some method is blocking the gui?
Yes, based on your descriptions in your original post.
It might not be a single a method. A very long chain of signals and slots has the same effect: Within the same thread, the function that emitted the first signal is blocked until until the last slot in the chain returns.
If yes, why it doesn't block when I add the result to the tableview? It works normally if I just print the
Result
information instead of showing?This line is difficult to understand. Do you mean "add the result to the model"? You can't add data to the view, after all. Also, please be more specific: How do you "print"? How do you "show"?
I'm guessing you meant: The program lags when
resultAvailable()
is emitted (which runsaddResult()
). In contrast, it doesn't lag if you simply print theResult
object's data to the console (using printf() or std::cout or qDebug()) without emitting the signal.Am I on the right track? If so, then
addResult()
might contain inefficient code.Quick check: What happens if you don't link your model to the table view (comment out
tableView->setModel(...)
? Does the UI still lag?If some method is blocking the gui, will I have to put this in another thread of there's a solution for that?
If the block is caused by the network requests or the parsing, then you can move it to another thread.
If the block is caused by inefficient code in your model, then you probably cannot move it to another thread. You'll have to optimize your model's code within the GUI thread.
If the block is caused by inefficient code in Qt, then you'll need to get the problem fixed upstream.
I have no idea as most of the functions are being called by signals & slots, I don't call the methods manually.
Regardless of whether your function is called manually or triggered by a signal, knowing how to profile your code is a useful skill. I recommend you spend some time to learn it. Here's one quick example, but there are more sophisticated tools out there: https://www.wikihow.com/Optimize-Your-Program's-Performance
Profiling helps you identify the cause of your lag. Without it, you'll have to resort to trial-and-error.
-
@JKSH said in Lagging window/gui when using realtime table view:
I'm guessing you meant: The program lags when resultAvailable() is emitted (which runs addResult()). In contrast, it doesn't lag if you simply print the Result object's data to the console (using printf() or std::cout or qDebug()) without emitting the signal.
Exactly, sorry for the wrong description.
Quick check: What happens if you don't link your model to the table view (comment out tableView->setModel(...)? Does the UI still lag?
It doesn't lag at all.
That is the entire model code:
#include "resultsmodel.hpp" #include "result.hpp" ResultsModel::ResultsModel(QObject *parent) : QAbstractTableModel(parent) { // ... } int ResultsModel::rowCount(const QModelIndex &) const { return mResults.size(); } int ResultsModel::columnCount(const QModelIndex &) const { return 5; } QVariant ResultsModel::data(const QModelIndex &index, int role) const { if (! index.isValid()) { return QVariant(); } if (index.row() >= mResults.size() || index.row() < 0) { return QVariant(); } auto result = mResults.at(index.row()); if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return result->filename().isEmpty() ? "?" : result->filename(); break; case 1: return result->url(); break; case 2: return result->source(); break; case 3: return result->fileSize().isEmpty() ? "?" : result->fileSize(); break; case 4: return result->isOnline() ? "Yes" : "No"; break; } } return QVariant(); } bool ResultsModel::setData(const QModelIndex &, const QVariant &, int) { return false; } QVariant ResultsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Filename"); break; case 1: return tr("Url"); break; case 2: return tr("Source"); break; case 3: return tr("Size"); break; case 4: return tr("Online"); break; default: return QVariant(); break; } } return QVariant(); } Qt::ItemFlags ResultsModel::flags(const QModelIndex &index) const { if (! index.isValid()) { return Qt::ItemIsEnabled; } return QAbstractTableModel::flags(index); } void ResultsModel::addResult(Result *result) { if (mResults.contains(result)) { return; } auto index = mResults.size(); beginInsertRows(QModelIndex(), index, index); mResults << result; endInsertRows(); } void ResultsModel::reset() { beginResetModel(); qDeleteAll(mResults.begin(), mResults.end()); mResults.clear(); endResetModel(); }
-
@Mr-Gisa said in Lagging window/gui when using realtime table view:
@JKSH said in Lagging window/gui when using realtime table view:
I'm guessing you meant: The program lags when resultAvailable() is emitted (which runs addResult()). In contrast, it doesn't lag if you simply print the Result object's data to the console (using printf() or std::cout or qDebug()) without emitting the signal.
Exactly, sorry for the wrong description.
Quick check: What happens if you don't link your model to the table view (comment out tableView->setModel(...)? Does the UI still lag?
It doesn't lag at all.
That is the entire model code:
Your code looks quite straightforward and clean.
I'm wondering if
beginInsertRows()
is being called too frequently. Some things you can try:-
Do some very basic profiling: Make every call to
addResult()
print a message to the console. Roughly how frequently is it being called? -
Use batched updates. Instead of doing beginInsertRows() - append - endInsertRows() every single time the
resultAvailable()
signal is emitted, store the new result in a temporary location but don't add it tomResults
yet. Every 0.5s, add all the new results at once:- Call
beginInsertRows()
once - Add all the available results
- Call
endInsertRows()
once
- Call
-
-
@JKSH with batched results you mean like this? https://doc.qt.io/qt-5/qtwidgets-itemviews-fetchmore-example.html
About the how many times the
addResult
is being called, it's a lot, it's like every half second a new result is added. -
@Mr-Gisa said in Lagging window/gui when using realtime table view:
if (mResults.contains(result)) { return; }
This is not a good idea...
- why should addResult() called twice with the same pointer? This can only happen due to wrong code on your side
- a linear lookup is maybe fast for < 100 lookups but not for huge data.
-
@Mr-Gisa said in Lagging window/gui when using realtime table view:
if (! index.isValid()) { return QVariant(); } if (index.row() >= mResults.size() || index.row() < 0) { return QVariant(); } auto result = mResults.at(index.row());
And here I would first check for the role, then the bounds and at last for the validity since this is the most expensive operation here.
-
@Christian-Ehrlicher I made the changes you pointed out and it helped a lot, it's still lagging, but way less than it was before. I can feel the gui freezing when trying to move, and as it's a lot of incoming data per second in the model you can really feel the lag in the gui.
I think you know a software called Wireshark, it was made using Qt and their table receives A LOT (way more than mine) of packets information and it doesn't lag at all, but in my application I can feel the lag when I try to move the window around while the results are being displayed in the table. -
Another idea is to collect some results and add them once in a second (or every n seconds) instead every single one.
-
I realized something. When I compile in release mode and run the application out of the Qt, like running the actual executable it doesn't lag. Why is that?
-
Because now the compiler don't need to generate debug information and compiles your code with optimizations.
-
You think I should leave that way getting results at real time or do the batched thing? What is the best alternative here?
-
@Mr-Gisa
Since you are planning on even higher payloads, you should test if release mode
can handle that or you simply need to batch them. -
It will have on average 100 or 200 thousand results.
-
@Mr-Gisa
and are you testing with that many now? -
5~10 thousands, I can't get to 100~200 cause I have to code the other APIs, but with that it's working normally at this point.
-
@Mr-Gisa
Ok, but you can postpone it until you have test data then and work on the other parts. -
Exactly, that is what I'm going to do. Thank you all for your help. If anything happen in the future I'll say it here.
I'm also going to get a copy with a friend of mine of his Intel Parallel Studio 2018 to check a few things in the application, I hope it works with Qt. -
@Mr-Gisa said in Lagging window/gui when using realtime table view:
Intel Parallel Studio 2018
Well its a compiler so good chance it can compile Qt.
-
I'm not going to use the compiler, but the Intel® Inspector and Intel® VTune™ Amplifier.
Intel® Inspector: Memory and Thread Debugger
Intel® VTune™ Amplifier: Performance Profiler -
@Mr-Gisa
Ok, but can it do it without touching the source code?