First call to QIcon::pixmap takes 180 milliseconds
-
I have a custom list view and model displaying user-specified filesystem entries (both files and directories are possible).
I wanted it to start displaying icons the OS uses for those filesystem entries, so i added this method, that is called from Model::data( role = Qt::DecorationRole )
static QHash< QString, QIcon > g_filesystemIconCache; const QIcon & Entry::getIcon() const { static QFileIconProvider iconProvider; // only one initialization needed auto iter = g_filesystemIconCache.find( this->path ); if (iter == g_filesystemIconCache.end()) { iter = g_filesystemIconCache.insert( this->path, iconProvider.icon( entryInfo ) ); } return iter.value(); }But soon i noticed my application loading time has increased noticably.
My first idea was that it is caused by the high-res icons used by Windows, so i modified the inner code block creating the icon toQIcon origIcon = iconProvider.icon( this->path ); QSize smallestSize = origIcon.availableSizes()[0]; QPixmap pixmap = origIcon.pixmap( smallestSize ); iter = g_filesystemIconCache.insert( this->path, QIcon( pixmap ) );and measured the time it took for each line and found out that the origIcon.pixmap( smallestSize ) took 180ms for the first item and then less than 1ms for the rest of items.
This only happens on Windows and it only happens with the icons provided by QFileIconProvider. If i load an internal resource icon instead, the total icon loading time is few milliseconds.
Do you know what is causing QIcon::pixmap to take so long and is there a workaround?
-
I have a custom list view and model displaying user-specified filesystem entries (both files and directories are possible).
I wanted it to start displaying icons the OS uses for those filesystem entries, so i added this method, that is called from Model::data( role = Qt::DecorationRole )
static QHash< QString, QIcon > g_filesystemIconCache; const QIcon & Entry::getIcon() const { static QFileIconProvider iconProvider; // only one initialization needed auto iter = g_filesystemIconCache.find( this->path ); if (iter == g_filesystemIconCache.end()) { iter = g_filesystemIconCache.insert( this->path, iconProvider.icon( entryInfo ) ); } return iter.value(); }But soon i noticed my application loading time has increased noticably.
My first idea was that it is caused by the high-res icons used by Windows, so i modified the inner code block creating the icon toQIcon origIcon = iconProvider.icon( this->path ); QSize smallestSize = origIcon.availableSizes()[0]; QPixmap pixmap = origIcon.pixmap( smallestSize ); iter = g_filesystemIconCache.insert( this->path, QIcon( pixmap ) );and measured the time it took for each line and found out that the origIcon.pixmap( smallestSize ) took 180ms for the first item and then less than 1ms for the rest of items.
This only happens on Windows and it only happens with the icons provided by QFileIconProvider. If i load an internal resource icon instead, the total icon loading time is few milliseconds.
Do you know what is causing QIcon::pixmap to take so long and is there a workaround?
What exact Qt and Windows version do you use? Please provide a minimal, compilable example to reproduce your issue.
@Axel-Spoerl: Looks similar to QTBUG-110416 ? -
What exact Qt and Windows version do you use? Please provide a minimal, compilable example to reproduce your issue.
@Axel-Spoerl: Looks similar to QTBUG-110416 ? -
@Youda008
Good morning,
just ran the reproducer locally on Qt 5.15.14 and the latest bleeding edge (6.7 dev), both developer builds in debug mode.
The codebase ofQFileIconProviderhasn't seen many changes and the stats don't show a big difference.
I use laptop computer, which is not incredibly fast. But it's got a fast SSD drive.
I don't want to exclude the possibility of a bug in Qt. However, if only the first call takes forever, I would find it worth checking for a local file caching issue.
I'd also consider changing to Qt 6 (in which case one line of code needs to be adapted, becauseQFileIconProvider::icon()doesn't like string arguments any more. Just calliconProvider.icon(entry);).
Cheers
Axel08:16:45: Debugging /home/axel/QtDev/build-IconList-Qt_6_7_0_dev_build/Debug/IconList ... #0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 61ms #2 : QIcon::pixmap() took 0ms #3 : QIcon::QIcon( QPixmap & ) took 0ms 08:17:00: Debugging of /home/axel/QtDev/build-IconList-Qt_6_7_0_dev_build/Debug/IconList has finished with exit code 0.08:21:13: Debugging /home/axel/QtDev/build-IconList-Qt_5_15_14_dev_build/Debug/IconList ... #0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 79ms #2 : QIcon::pixmap() took 0ms #3 : QIcon::QIcon( QPixmap & ) took 0ms 08:21:29: Debugging of /home/axel/QtDev/build-IconList-Qt_5_15_14_dev_build/Debug/IconList has finished with exit code 0. -
@Youda008
Good morning,
just ran the reproducer locally on Qt 5.15.14 and the latest bleeding edge (6.7 dev), both developer builds in debug mode.
The codebase ofQFileIconProviderhasn't seen many changes and the stats don't show a big difference.
I use laptop computer, which is not incredibly fast. But it's got a fast SSD drive.
I don't want to exclude the possibility of a bug in Qt. However, if only the first call takes forever, I would find it worth checking for a local file caching issue.
I'd also consider changing to Qt 6 (in which case one line of code needs to be adapted, becauseQFileIconProvider::icon()doesn't like string arguments any more. Just calliconProvider.icon(entry);).
Cheers
Axel08:16:45: Debugging /home/axel/QtDev/build-IconList-Qt_6_7_0_dev_build/Debug/IconList ... #0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 61ms #2 : QIcon::pixmap() took 0ms #3 : QIcon::QIcon( QPixmap & ) took 0ms 08:17:00: Debugging of /home/axel/QtDev/build-IconList-Qt_6_7_0_dev_build/Debug/IconList has finished with exit code 0.08:21:13: Debugging /home/axel/QtDev/build-IconList-Qt_5_15_14_dev_build/Debug/IconList ... #0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 79ms #2 : QIcon::pixmap() took 0ms #3 : QIcon::QIcon( QPixmap & ) took 0ms 08:21:29: Debugging of /home/axel/QtDev/build-IconList-Qt_5_15_14_dev_build/Debug/IconList has finished with exit code 0.@Axel-Spoerl Thank you for looking into it.
Interestingly, in your results it's the
QFileIconProvider::icon()that takes the most time, while in my tests it's theQIcon::pixmap().#0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 0ms #2 : QIcon::pixmap() took 179ms #3 : QIcon::QIcon( QPixmap & ) took 0ms #4 : QDirIterator::next() took 1ms #5 : QFileIconProvider::icon() took 0ms #6 : QIcon::pixmap() took 12ms #7 : QIcon::QIcon( QPixmap & ) took 0ms #8 : QDirIterator::next() took 0ms #9 : QFileIconProvider::icon() took 0ms #10: QIcon::pixmap() took 11ms #11: QIcon::QIcon( QPixmap & ) took 0msIt looks to me as if the
QFileIconProvider::icon()orQIcon::pixmap()performed some heavy on-demand initialization. I am wondering what that could be and if it can be prevented.Can you please add more files to the directory of the executable from which the code loads the icons, so that we can see what happens with the consequent calls?
Your time might not be as large as mine, but you might still see the same big difference between the first call and the other calls.In the meantime i will try to investiate with ProcessMonitor, because i cannot debug the Qt's code, because i use pre-built packages.
-
@Axel-Spoerl Thank you for looking into it.
Interestingly, in your results it's the
QFileIconProvider::icon()that takes the most time, while in my tests it's theQIcon::pixmap().#0 : QDirIterator::next() took 0ms #1 : QFileIconProvider::icon() took 0ms #2 : QIcon::pixmap() took 179ms #3 : QIcon::QIcon( QPixmap & ) took 0ms #4 : QDirIterator::next() took 1ms #5 : QFileIconProvider::icon() took 0ms #6 : QIcon::pixmap() took 12ms #7 : QIcon::QIcon( QPixmap & ) took 0ms #8 : QDirIterator::next() took 0ms #9 : QFileIconProvider::icon() took 0ms #10: QIcon::pixmap() took 11ms #11: QIcon::QIcon( QPixmap & ) took 0msIt looks to me as if the
QFileIconProvider::icon()orQIcon::pixmap()performed some heavy on-demand initialization. I am wondering what that could be and if it can be prevented.Can you please add more files to the directory of the executable from which the code loads the icons, so that we can see what happens with the consequent calls?
Your time might not be as large as mine, but you might still see the same big difference between the first call and the other calls.In the meantime i will try to investiate with ProcessMonitor, because i cannot debug the Qt's code, because i use pre-built packages.
@Youda008 said in First call to QIcon::pixmap takes 180 milliseconds:
e Qt's code, because i use pre-built packages.
But even there you can install the debug symbols and sources.
