1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtconcurrentiteratekernel.h"
43
44#if defined(Q_OS_MAC)
45#include <mach/mach.h>
46#include <mach/mach_time.h>
47#include <unistd.h>
48#elif defined(Q_OS_UNIX)
49#if defined(Q_OS_HURD)
50#include <sys/time.h>
51#endif
52#include <time.h>
53#include <unistd.h>
54#elif defined(Q_OS_WIN)
55#include <qt_windows.h>
56#endif
57
58#include "private/qfunctions_p.h"
59
60
61#ifndef QT_NO_CONCURRENT
62
63QT_BEGIN_NAMESPACE
64
65enum {
66 TargetRatio = 100,
67 MedianSize = 7
68};
69
70#if defined(Q_OS_MAC)
71
72static qint64 getticks()
73{
74 return mach_absolute_time();
75}
76
77#elif defined(Q_OS_UNIX)
78
79
80static qint64 getticks()
81{
82#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
83 clockid_t clockId;
84
85#ifndef _POSIX_THREAD_CPUTIME
86 clockId = CLOCK_REALTIME;
87#elif (_POSIX_THREAD_CPUTIME-0 <= 0)
88 // if we don't have CLOCK_THREAD_CPUTIME_ID, we have to just use elapsed realtime instead
89 clockId = CLOCK_REALTIME;
90
91# if (_POSIX_THREAD_CPUTIME-0 == 0)
92 // detect availablility of CLOCK_THREAD_CPUTIME_ID
93 static long useThreadCpuTime = -2;
94 if (useThreadCpuTime == -2) {
95 // sysconf() will return either -1 or _POSIX_VERSION (don't care about thread races here)
96 useThreadCpuTime = sysconf(_SC_THREAD_CPUTIME);
97 }
98 if (useThreadCpuTime != -1)
99 clockId = CLOCK_THREAD_CPUTIME_ID;
100# endif
101#else
102 clockId = CLOCK_THREAD_CPUTIME_ID;
103#endif
104
105 struct timespec ts;
106 if (clock_gettime(clockId, &ts) == -1)
107 return 0;
108 return (ts.tv_sec * 1000000000) + ts.tv_nsec;
109#else
110
111#ifdef Q_OS_SYMBIAN
112 return clock();
113#else
114 // no clock_gettime(), fall back to wall time
115 struct timeval tv;
116 gettimeofday(&tv, 0);
117 return (tv.tv_sec * 1000000) + tv.tv_usec;
118#endif
119
120#endif
121}
122
123#elif defined(Q_OS_WIN)
124
125static qint64 getticks()
126{
127 LARGE_INTEGER x;
128 if (!QueryPerformanceCounter(&x))
129 return 0;
130 return x.QuadPart;
131}
132
133#endif
134
135static double elapsed(qint64 after, qint64 before)
136{
137 return double(after - before);
138}
139
140namespace QtConcurrent {
141
142/*! \internal
143
144*/
145BlockSizeManager::BlockSizeManager(int iterationCount)
146: maxBlockSize(iterationCount / (QThreadPool::globalInstance()->maxThreadCount() * 2)),
147 beforeUser(0), afterUser(0),
148 controlPartElapsed(MedianSize), userPartElapsed(MedianSize),
149 m_blockSize(1)
150{ }
151
152// Records the time before user code.
153void BlockSizeManager::timeBeforeUser()
154{
155 if (blockSizeMaxed())
156 return;
157
158 beforeUser = getticks();
159 controlPartElapsed.addValue(elapsed(beforeUser, afterUser));
160}
161
162 // Records the time after user code and adjust the block size if we are spending
163 // to much time in the for control code compared with the user code.
164void BlockSizeManager::timeAfterUser()
165{
166 if (blockSizeMaxed())
167 return;
168
169 afterUser = getticks();
170 userPartElapsed.addValue(elapsed(afterUser, beforeUser));
171
172 if (controlPartElapsed.isMedianValid() == false)
173 return;
174
175 if (controlPartElapsed.median() * TargetRatio < userPartElapsed.median())
176 return;
177
178 m_blockSize = qMin(m_blockSize * 2, maxBlockSize);
179
180#ifdef QTCONCURRENT_FOR_DEBUG
181 qDebug() << QThread::currentThread() << "adjusting block size" << controlPartElapsed.median() << userPartElapsed.median() << m_blockSize;
182#endif
183
184 // Reset the medians after adjusting the block size so we get
185 // new measurements with the new block size.
186 controlPartElapsed.reset();
187 userPartElapsed.reset();
188}
189
190int BlockSizeManager::blockSize()
191{
192 return m_blockSize;
193}
194
195} // namespace QtConcurrent
196
197QT_END_NAMESPACE
198
199#endif // QT_NO_CONCURRENT
200