summaryrefslogtreecommitdiffstats
path: root/src/concurrent
diff options
context:
space:
mode:
Diffstat (limited to 'src/concurrent')
-rw-r--r--src/concurrent/qtconcurrentiteratekernel.cpp52
-rw-r--r--src/concurrent/qtconcurrentiteratekernel.h28
-rw-r--r--src/concurrent/qtconcurrentmedian.h66
3 files changed, 145 insertions, 1 deletions
diff --git a/src/concurrent/qtconcurrentiteratekernel.cpp b/src/concurrent/qtconcurrentiteratekernel.cpp
index 49056406c3..3b9b186b39 100644
--- a/src/concurrent/qtconcurrentiteratekernel.cpp
+++ b/src/concurrent/qtconcurrentiteratekernel.cpp
@@ -182,6 +182,58 @@ int BlockSizeManager::blockSize()
return m_blockSize;
}
+/*! \internal
+
+*/
+BlockSizeManagerV2::BlockSizeManagerV2(int iterationCount)
+ : maxBlockSize(iterationCount / (QThreadPool::globalInstance()->maxThreadCount() * 2)),
+ beforeUser(0), afterUser(0),
+ m_blockSize(1)
+{ }
+
+// Records the time before user code.
+void BlockSizeManagerV2::timeBeforeUser()
+{
+ if (blockSizeMaxed())
+ return;
+
+ beforeUser = getticks();
+ controlPartElapsed.addValue(elapsed(beforeUser, afterUser));
+}
+
+ // Records the time after user code and adjust the block size if we are spending
+ // to much time in the for control code compared with the user code.
+void BlockSizeManagerV2::timeAfterUser()
+{
+ if (blockSizeMaxed())
+ return;
+
+ afterUser = getticks();
+ userPartElapsed.addValue(elapsed(afterUser, beforeUser));
+
+ if (controlPartElapsed.isMedianValid() == false)
+ return;
+
+ if (controlPartElapsed.median() * TargetRatio < userPartElapsed.median())
+ return;
+
+ m_blockSize = qMin(m_blockSize * 2, maxBlockSize);
+
+#ifdef QTCONCURRENT_FOR_DEBUG
+ qDebug() << QThread::currentThread() << "adjusting block size" << controlPartElapsed.median() << userPartElapsed.median() << m_blockSize;
+#endif
+
+ // Reset the medians after adjusting the block size so we get
+ // new measurements with the new block size.
+ controlPartElapsed.reset();
+ userPartElapsed.reset();
+}
+
+int BlockSizeManagerV2::blockSize()
+{
+ return m_blockSize;
+}
+
} // namespace QtConcurrent
QT_END_NAMESPACE
diff --git a/src/concurrent/qtconcurrentiteratekernel.h b/src/concurrent/qtconcurrentiteratekernel.h
index 32acf03338..40e2c6c115 100644
--- a/src/concurrent/qtconcurrentiteratekernel.h
+++ b/src/concurrent/qtconcurrentiteratekernel.h
@@ -82,6 +82,32 @@ private:
Q_DISABLE_COPY(BlockSizeManager)
};
+// ### Qt6: Replace BlockSizeManager with V2 implementation
+class Q_CONCURRENT_EXPORT BlockSizeManagerV2
+{
+public:
+ explicit BlockSizeManagerV2(int iterationCount);
+
+ void timeBeforeUser();
+ void timeAfterUser();
+ int blockSize();
+
+private:
+ inline bool blockSizeMaxed()
+ {
+ return (m_blockSize >= maxBlockSize);
+ }
+
+ const int maxBlockSize;
+ qint64 beforeUser;
+ qint64 afterUser;
+ MedianDouble controlPartElapsed;
+ MedianDouble userPartElapsed;
+ int m_blockSize;
+
+ Q_DISABLE_COPY(BlockSizeManagerV2)
+};
+
template <typename T>
class ResultReporter
{
@@ -190,7 +216,7 @@ public:
ThreadFunctionResult forThreadFunction()
{
- BlockSizeManager blockSizeManager(iterationCount);
+ BlockSizeManagerV2 blockSizeManager(iterationCount);
ResultReporter<T> resultReporter(this);
for(;;) {
diff --git a/src/concurrent/qtconcurrentmedian.h b/src/concurrent/qtconcurrentmedian.h
index 2ae7954b7a..e35e2aec70 100644
--- a/src/concurrent/qtconcurrentmedian.h
+++ b/src/concurrent/qtconcurrentmedian.h
@@ -121,6 +121,72 @@ private:
bool dirty;
};
+// ### Qt6: Drop Median<double> in favor of this faster MedianDouble
+class MedianDouble
+{
+public:
+ enum { BufferSize = 7 };
+
+ MedianDouble()
+ : currentMedian(), currentIndex(0), valid(false), dirty(true)
+ {
+ }
+
+ void reset()
+ {
+ std::fill_n(values, static_cast<int>(BufferSize), 0.0);
+ currentIndex = 0;
+ valid = false;
+ dirty = true;
+ }
+
+ void addValue(double value)
+ {
+ ++currentIndex;
+ if (currentIndex == BufferSize) {
+ currentIndex = 0;
+ valid = true;
+ }
+
+ // Only update the cached median value when we have to, that
+ // is when the new value is on then other side of the median
+ // compared to the current value at the index.
+ const double currentIndexValue = values[currentIndex];
+ if ((currentIndexValue > currentMedian && currentMedian > value)
+ || (currentMedian > currentIndexValue && value > currentMedian)) {
+ dirty = true;
+ }
+
+ values[currentIndex] = value;
+ }
+
+ bool isMedianValid() const
+ {
+ return valid;
+ }
+
+ double median()
+ {
+ if (dirty) {
+ dirty = false;
+
+ double sorted[BufferSize];
+ ::memcpy(&sorted, &values, sizeof(sorted));
+ std::sort(sorted, sorted + static_cast<int>(BufferSize));
+ currentMedian = sorted[BufferSize / 2];
+ }
+
+ return currentMedian;
+ }
+
+private:
+ double values[BufferSize];
+ double currentMedian;
+ int currentIndex;
+ bool valid;
+ bool dirty;
+};
+
} // namespace QtConcurrent
#endif //Q_QDOC