PDA

View Full Version : QT inconsistent performance !!!



gontham
12th November 2010, 08:17
Hello,

I have an email model displayed in a QTreeView with check boxes (~ 1500 emails).

I have a function that loads a string of email addresses(seperated by commas) saved in a SQLite database and translates them to a QStringList (~ 900 emails).
Then I iterate over the email model, if an email address is found in the QStringList the checkbox is checked, otherwise its unchecked.



QTime time1 = QTime::currentTime();
QStringList emails = campaignModel->data(campaignModel->index(index,5)).toString().split(",",QString::SkipEmptyParts);
QStandardItem *parentItem;

for (int i=0;i<emailModel->rowCount();i++) {
qApp->processEvents();
parentItem = emailModel->item(i,0);
if (emails.contains(parentItem->data(0).toString()))
parentItem->setCheckState(Qt::Checked);
else
parentItem->setCheckState(Qt::Unchecked);
}
QTime time2 = QTime::currentTime();
qDebug() << "Benchmark0: " << time1.msecsTo(time2);

My question is how come the first time i run the compiled exe file it takes about 30 msecs to execute the function.
But whenever i call the function after that, it takes about 300 msec ?!

any ideas or feedback would be appreciated ?
Thanks.

JPNaude
12th November 2010, 08:29
Maybe take out qApp->processEvents() and check again. The execution time of that line will depend on the number of events in the QApplication's event queue.

gontham
12th November 2010, 08:59
Thanks for the reply JPNaude,

I removed that command and i got a slight improvement on the subsequent calls,
The first run is still about 30 msec and around 250 msec for all subsequent runs.
I still can't explain that huge difference.

high_flyer
12th November 2010, 09:05
in order to narrow down where the bottleneck is, try putting 'time1' just before the 'for' loop.
See if the change is in the 'for' or in the model query.
My guess its in the model query, and if so, you have to check your code there.

gontham
12th November 2010, 09:33
Hello high_flyer,

Thanks for the suggestion, I ran a couple of tests and it turns out the delay is comming for the following commands:

parentItem->setCheckState(Qt::Checked);
and:

parentItem->setCheckState(Qt::Unchecked);

When i changed the code to the one shown below the for loop takes about 30 msec on every run:

QTime time1 = QTime::currentTime();
for (int i=0;i<emailModel->rowCount();i++) {
//qApp->processEvents();
parentItem = emailModel->item(i,0);
if (emails.contains(parentItem->data(0).toString())){}
//parentItem->setCheckState(Qt::Checked);
else{}
//parentItem->setCheckState(Qt::Unchecked);
}
QTime time2 = QTime::currentTime();
qDebug() << "Benchmark4: " << time1.msecsTo(time2);

Is there a workaround to this ? or maybe a more efficient way to achieve what i'm trying to do ?

high_flyer
12th November 2010, 09:43
Is there a workaround to this ?
Well its like JPNaude said, each setCheckState() triggers an event, it is probably many in your case.
One way perhaps is to put this part of a code in to worker thread, and send signals to the items from it.
This will ensure your loop runs in constant time, but it might still take longer for the GUI to update the all checks.
But 300 ms is not such a bad time, its a 0.3 of sec, for ~1500 gui items I think its ok... I mean, this is email app not real time app...

Oh, another thing -
you can change the design as follows:
you add a bool to your items to hold their checked state, but actually set the check box only on visible items (in a separate loop maybe), which will usually be far less than 1500.

SixDegrees
12th November 2010, 12:02
You might also try calling blockSignals(true/false) before and after your setCheckState() calls. Although this could be bad if anything else needs to hear about the change.

gontham
12th November 2010, 23:51
Thanks to all for the feedback.

I used SixDegrees idea to blockSignals, and i manually called the QTreeView update function on the items and that did the trick.



QTime time1 = QTime::currentTime();
emailModel->blockSignals(true);
ui->emailView->blockSignals(true);
for (int i=0;i<emailModel->rowCount();i++) {
parentItem = emailModel->item(i,0);
if (emails.contains(parentItem->data(0).toString()))
parentItem->setCheckState(Qt::Checked);
else
parentItem->setCheckState(Qt::Unchecked);
ui->emailView->update(parentItem->index());
}
ui->emailView->blockSignals(false);
emailModel->blockSignals(false);
QTime time2 = QTime::currentTime();
qDebug() << "Benchmark4: " << time1.msecsTo(time2);