Avoid heap allocations in Median class
Create a MedianDouble class and V2 version of BlockSizeManager, which use a fixed size array of double (since we always use 7 elements to calculate the median anyway). Change-Id: Ife90b90336a9a8c037b90726dee4cd2a1b8b6cd9 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
c3850dd636
commit
24d851dcd2
@ -182,6 +182,58 @@ int BlockSizeManager::blockSize()
|
|||||||
return m_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
|
} // namespace QtConcurrent
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -82,6 +82,32 @@ private:
|
|||||||
Q_DISABLE_COPY(BlockSizeManager)
|
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>
|
template <typename T>
|
||||||
class ResultReporter
|
class ResultReporter
|
||||||
{
|
{
|
||||||
@ -190,7 +216,7 @@ public:
|
|||||||
|
|
||||||
ThreadFunctionResult forThreadFunction()
|
ThreadFunctionResult forThreadFunction()
|
||||||
{
|
{
|
||||||
BlockSizeManager blockSizeManager(iterationCount);
|
BlockSizeManagerV2 blockSizeManager(iterationCount);
|
||||||
ResultReporter<T> resultReporter(this);
|
ResultReporter<T> resultReporter(this);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -121,6 +121,72 @@ private:
|
|||||||
bool dirty;
|
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
|
} // namespace QtConcurrent
|
||||||
|
|
||||||
#endif //Q_QDOC
|
#endif //Q_QDOC
|
||||||
|
Loading…
x
Reference in New Issue
Block a user