From: Peter Penz Date: Tue, 2 Aug 2011 17:47:06 +0000 (+0200) Subject: Improve performance for creating previews X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/8ea76d0a0e67fbf03de5c2a10a77077b8fe51c08 Improve performance for creating previews The overall time for creating previews is faster the more items are passed to KIO::previewJob() in parallel instead of passing e.g. only 100 items once and start several KIO::previewJobs sequentially. However in the worst case KIO::previewJob() might block the application for several seconds if the MIME-type of the passed KFileItems are unknown and e.g. 10000 items are forwarded. So KFileItemModelRolesUpdater will now take care to resolve as many MIME-types as possible until a timeout is reached and will only pass those items to KIO::previewJob(). For huge image folders, where the MIME-type can be determined very fast, this means that the overall time for creating previews will decrease without blocking the application. For "worst case" directories where resolving the MIME-type can get very expensive this approach assures no blocking of the user-interface although the overall time until all previews are generated might slightly increase. --- diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 4d36a4e05..5b589a9d5 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -44,6 +44,14 @@ #define KFILEITEMMODELROLESUPDATER_DEBUG namespace { + // Maximum time in ms that the KFileItemModelRolesUpdater + // may perform a blocking operation + const int MaxBlockTimeout = 200; + + // Maximum number of items that will get resolved synchronously. + // The value should roughly represent the number of maximum visible + // items, as it does not make sense to resolve more items synchronously + // and probably reach the MaxBlockTimeout because of invisible items. const int MaxResolveItemsCount = 100; } @@ -344,9 +352,8 @@ void KFileItemModelRolesUpdater::slotPreviewJobFinished(KJob* job) return; } - const KFileItemList visibleItems = sortedItems(m_pendingVisibleItems); - const KFileItemList invisibleItems = itemSubSet(m_pendingInvisibleItems, MaxResolveItemsCount - visibleItems.count()); - startPreviewJob(visibleItems + invisibleItems); + const KFileItemList visibleItems = sortedItems(m_pendingVisibleItems); + startPreviewJob(visibleItems + m_pendingInvisibleItems.toList()); } void KFileItemModelRolesUpdater::resolvePendingRoles() @@ -358,10 +365,9 @@ void KFileItemModelRolesUpdater::resolvePendingRoles() || m_roles.contains("type"); const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll; - // Resolving the MIME type can be expensive. Assure that not more than 200 ms are + // Resolving the MIME type can be expensive. Assure that not more than MaxBlockTimeout ms are // spend for resolving them synchronously. Usually this is more than enough to determine // all visible items, but there are corner cases where this limit gets easily exceeded. - const int MaxTime = 200; QElapsedTimer timer; timer.start(); @@ -377,7 +383,7 @@ void KFileItemModelRolesUpdater::resolvePendingRoles() } ++resolvedCount; - if (timer.elapsed() > MaxTime) { + if (timer.elapsed() > MaxBlockTimeout) { break; } } @@ -397,7 +403,7 @@ void KFileItemModelRolesUpdater::resolvePendingRoles() } int index = 0; - while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxTime) { + while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxBlockTimeout) { const KFileItem item = invisibleItems.at(index); applyResolvedRoles(item, resolveHint); @@ -418,8 +424,9 @@ void KFileItemModelRolesUpdater::resolvePendingRoles() } #ifdef KFILEITEMMODELROLESUPDATER_DEBUG - if (timer.elapsed() > MaxTime) { - kDebug() << "Maximum time exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() + if (timer.elapsed() > MaxBlockTimeout) { + kDebug() << "Maximum time of" << MaxBlockTimeout + << "ms exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count() << "invisible:" << m_pendingInvisibleItems.count(); } kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed(); @@ -482,16 +489,28 @@ void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items) const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128) ? QSize(256, 256) : QSize(128, 128); - KJob* job; - if (items.count() <= MaxResolveItemsCount) { - job = KIO::filePreview(items, cacheSize, &m_enabledPlugins); - } else { - KFileItemList itemsSubSet; - for (int i = 0; i <= MaxResolveItemsCount; ++i) { - itemsSubSet.append(items.at(i)); + // KIO::filePreview() will request the MIME-type of all passed items, which (in the + // worst case) might block the application for several seconds. To prevent such + // a blocking the MIME-type of the items will determined until the MaxBlockTimeout + // has been reached and only those items will get passed. As soon as the MIME-type + // has been resolved once KIO::filePreview() can already access the resolved + // MIME-type in a fast way. + QElapsedTimer timer; + timer.start(); + KFileItemList itemSubSet; + for (int i = 0; i < items.count(); ++i) { + KFileItem item = items.at(i); + item.determineMimeType(); + itemSubSet.append(items.at(i)); + if (timer.elapsed() > MaxBlockTimeout) { +#ifdef KFILEITEMMODELROLESUPDATER_DEBUG + kDebug() << "Maximum time of" << MaxBlockTimeout << "ms exceeded, creating only previews for" + << (i + 1) << "items," << (items.count() - (i + 1)) << "will be resolved later"; +#endif + break; } - job = KIO::filePreview(itemsSubSet, cacheSize, &m_enabledPlugins); } + KJob* job = KIO::filePreview(itemSubSet, cacheSize, &m_enabledPlugins); connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)), this, SLOT(slotGotPreview(KFileItem,QPixmap))); @@ -711,24 +730,6 @@ KFileItemList KFileItemModelRolesUpdater::sortedItems(const QSet& ite return itemList; } -KFileItemList KFileItemModelRolesUpdater::itemSubSet(const QSet& items, int count) -{ - KFileItemList itemList; - - int index = 0; - QSetIterator it(items); - while (it.hasNext() && index < count) { - const KFileItem item = it.next(); - if (item.isNull()) { - continue; - } - itemList.append(item); - ++index; - } - - return itemList; -} - int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path) { #ifdef Q_WS_WIN diff --git a/src/kitemviews/kfileitemmodelrolesupdater.h b/src/kitemviews/kfileitemmodelrolesupdater.h index 4931f9d64..3b173567e 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.h +++ b/src/kitemviews/kfileitemmodelrolesupdater.h @@ -137,7 +137,6 @@ private: KFileItemList sortedItems(const QSet& items) const; - static KFileItemList itemSubSet(const QSet& items, int count); static int subDirectoriesCount(const QString& path); private: