| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief CPU warm-up utility, used to counteract CPU throttling. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuCPUWarmup.hpp" |
| #include "deDefs.hpp" |
| #include "deMath.h" |
| #include "deClock.h" |
| |
| #include <algorithm> |
| |
| namespace tcu |
| { |
| |
| namespace warmupCPUInternal |
| { |
| |
| volatile Dummy g_dummy; |
| |
| }; |
| |
| template <typename T, int Size> |
| static inline float floatMedian (const T (&v)[Size]) |
| { |
| T temp[Size]; |
| for (int i = 0; i < Size; i++) |
| temp[i] = v[i]; |
| |
| std::sort(DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp)); |
| |
| return Size % 2 == 0 |
| ? 0.5f * ((float)temp[Size/2-1] + (float)temp[Size/2]) |
| : (float)temp[Size/2]; |
| } |
| |
| template <typename T, int Size> |
| static inline float floatRelativeMedianAbsoluteDeviation (const T (&v)[Size]) |
| { |
| const float median = floatMedian(v); |
| float absoluteDeviations[Size]; |
| |
| for (int i = 0; i < Size; i++) |
| absoluteDeviations[i] = deFloatAbs((float)v[i] - median); |
| |
| return floatMedian(absoluteDeviations) / median; |
| } |
| |
| static inline float dummyComputation (float initial, int numIterations) |
| { |
| float a = initial; |
| int b = 123; |
| |
| for (int i = 0; i < numIterations; i++) |
| { |
| // Arbitrary computations. |
| for (int j = 0; j < 4; j++) |
| { |
| a = deFloatCos(a + (float)b); |
| b = (b + 63) % 107 + de::abs((int)(a*10.0f)); |
| } |
| } |
| |
| return a + (float)b; |
| } |
| |
| void warmupCPU (void) |
| { |
| float dummy = *warmupCPUInternal::g_dummy.m_v; |
| int computationSize = 1; |
| |
| // Do a rough calibration for computationSize to get dummyComputation's running time above a certain threshold. |
| while (computationSize < 1<<30) // \note This condition is unlikely to be met. The "real" loop exit is the break below. |
| { |
| const float singleMeasurementThreshold = 10000.0f; |
| const int numMeasurements = 3; |
| deInt64 times[numMeasurements]; |
| |
| for (int i = 0; i < numMeasurements; i++) |
| { |
| const deUint64 startTime = deGetMicroseconds(); |
| dummy = dummyComputation(dummy, computationSize); |
| times[i] = (deInt64)(deGetMicroseconds() - startTime); |
| } |
| |
| if (floatMedian(times) >= singleMeasurementThreshold) |
| break; |
| |
| computationSize *= 2; |
| } |
| |
| // Do dummyComputations until running time seems stable enough. |
| { |
| const int maxNumMeasurements = 50; |
| const int numConsecutiveMeasurementsRequired = 5; |
| const float relativeMedianAbsoluteDeviationThreshold = 0.05f; |
| deInt64 latestTimes[numConsecutiveMeasurementsRequired]; |
| |
| for (int measurementNdx = 0; |
| |
| measurementNdx < maxNumMeasurements && |
| (measurementNdx < numConsecutiveMeasurementsRequired || |
| floatRelativeMedianAbsoluteDeviation(latestTimes) > relativeMedianAbsoluteDeviationThreshold); |
| |
| measurementNdx++) |
| { |
| const deUint64 startTime = deGetMicroseconds(); |
| dummy = dummyComputation(dummy, computationSize); |
| latestTimes[measurementNdx % numConsecutiveMeasurementsRequired] = (deInt64)(deGetMicroseconds() - startTime); |
| } |
| } |
| |
| *warmupCPUInternal::g_dummy.m_v = dummy; |
| } |
| |
| } // tcu |