/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtCore module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qtconcurrentiteratekernel.h" | |
#if defined(Q_OS_MAC) | |
#include <mach/mach.h> | |
#include <mach/mach_time.h> | |
#include <unistd.h> | |
#elif defined(Q_OS_UNIX) | |
#if defined(Q_OS_HURD) | |
#include <sys/time.h> | |
#endif | |
#include <time.h> | |
#include <unistd.h> | |
#elif defined(Q_OS_WIN) | |
#include <qt_windows.h> | |
#endif | |
#include "private/qfunctions_p.h" | |
#ifndef QT_NO_CONCURRENT | |
QT_BEGIN_NAMESPACE | |
enum { | |
TargetRatio = 100, | |
MedianSize = 7 | |
}; | |
#if defined(Q_OS_MAC) | |
static qint64 getticks() | |
{ | |
return mach_absolute_time(); | |
} | |
#elif defined(Q_OS_UNIX) | |
static qint64 getticks() | |
{ | |
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) | |
clockid_t clockId; | |
#ifndef _POSIX_THREAD_CPUTIME | |
clockId = CLOCK_REALTIME; | |
#elif (_POSIX_THREAD_CPUTIME-0 <= 0) | |
// if we don't have CLOCK_THREAD_CPUTIME_ID, we have to just use elapsed realtime instead | |
clockId = CLOCK_REALTIME; | |
# if (_POSIX_THREAD_CPUTIME-0 == 0) | |
// detect availablility of CLOCK_THREAD_CPUTIME_ID | |
static long useThreadCpuTime = -2; | |
if (useThreadCpuTime == -2) { | |
// sysconf() will return either -1 or _POSIX_VERSION (don't care about thread races here) | |
useThreadCpuTime = sysconf(_SC_THREAD_CPUTIME); | |
} | |
if (useThreadCpuTime != -1) | |
clockId = CLOCK_THREAD_CPUTIME_ID; | |
# endif | |
#else | |
clockId = CLOCK_THREAD_CPUTIME_ID; | |
#endif | |
struct timespec ts; | |
if (clock_gettime(clockId, &ts) == -1) | |
return 0; | |
return (ts.tv_sec * 1000000000) + ts.tv_nsec; | |
#else | |
#ifdef Q_OS_SYMBIAN | |
return clock(); | |
#else | |
// no clock_gettime(), fall back to wall time | |
struct timeval tv; | |
gettimeofday(&tv, 0); | |
return (tv.tv_sec * 1000000) + tv.tv_usec; | |
#endif | |
#endif | |
} | |
#elif defined(Q_OS_WIN) | |
static qint64 getticks() | |
{ | |
LARGE_INTEGER x; | |
if (!QueryPerformanceCounter(&x)) | |
return 0; | |
return x.QuadPart; | |
} | |
#endif | |
static double elapsed(qint64 after, qint64 before) | |
{ | |
return double(after - before); | |
} | |
namespace QtConcurrent { | |
/*! \internal | |
*/ | |
BlockSizeManager::BlockSizeManager(int iterationCount) | |
: maxBlockSize(iterationCount / (QThreadPool::globalInstance()->maxThreadCount() * 2)), | |
beforeUser(0), afterUser(0), | |
controlPartElapsed(MedianSize), userPartElapsed(MedianSize), | |
m_blockSize(1) | |
{ } | |
// Records the time before user code. | |
void BlockSizeManager::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 BlockSizeManager::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 BlockSizeManager::blockSize() | |
{ | |
return m_blockSize; | |
} | |
} // namespace QtConcurrent | |
QT_END_NAMESPACE | |
#endif // QT_NO_CONCURRENT |