1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief CPU warm-up utility, used to counteract CPU throttling. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuCPUWarmup.hpp" 25 #include "deDefs.hpp" 26 #include "deMath.h" 27 #include "deClock.h" 28 29 #include <algorithm> 30 31 namespace tcu 32 { 33 34 namespace warmupCPUInternal 35 { 36 37 volatile Dummy g_dummy; 38 39 }; 40 41 template <typename T, int Size> 42 static inline float floatMedian (const T (&v)[Size]) 43 { 44 T temp[Size]; 45 for (int i = 0; i < Size; i++) 46 temp[i] = v[i]; 47 48 std::sort(DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp)); 49 50 return Size % 2 == 0 51 ? 0.5f * ((float)temp[Size/2-1] + (float)temp[Size/2]) 52 : (float)temp[Size/2]; 53 } 54 55 template <typename T, int Size> 56 static inline float floatRelativeMedianAbsoluteDeviation (const T (&v)[Size]) 57 { 58 const float median = floatMedian(v); 59 float absoluteDeviations[Size]; 60 61 for (int i = 0; i < Size; i++) 62 absoluteDeviations[i] = deFloatAbs((float)v[i] - median); 63 64 return floatMedian(absoluteDeviations) / median; 65 } 66 67 static inline float dummyComputation (float initial, int numIterations) 68 { 69 float a = initial; 70 int b = 123; 71 72 for (int i = 0; i < numIterations; i++) 73 { 74 // Arbitrary computations. 75 for (int j = 0; j < 4; j++) 76 { 77 a = deFloatCos(a + (float)b); 78 b = (b + 63) % 107 + de::abs((int)(a*10.0f)); 79 } 80 } 81 82 return a + (float)b; 83 } 84 85 void warmupCPU (void) 86 { 87 float dummy = *warmupCPUInternal::g_dummy.m_v; 88 int computationSize = 1; 89 90 // Do a rough calibration for computationSize to get dummyComputation's running time above a certain threshold. 91 while (computationSize < 1<<30) // \note This condition is unlikely to be met. The "real" loop exit is the break below. 92 { 93 const float singleMeasurementThreshold = 10000.0f; 94 const int numMeasurements = 3; 95 deInt64 times[numMeasurements]; 96 97 for (int i = 0; i < numMeasurements; i++) 98 { 99 const deUint64 startTime = deGetMicroseconds(); 100 dummy = dummyComputation(dummy, computationSize); 101 times[i] = (deInt64)(deGetMicroseconds() - startTime); 102 } 103 104 if (floatMedian(times) >= singleMeasurementThreshold) 105 break; 106 107 computationSize *= 2; 108 } 109 110 // Do dummyComputations until running time seems stable enough. 111 { 112 const int maxNumMeasurements = 50; 113 const int numConsecutiveMeasurementsRequired = 5; 114 const float relativeMedianAbsoluteDeviationThreshold = 0.05f; 115 deInt64 latestTimes[numConsecutiveMeasurementsRequired]; 116 117 for (int measurementNdx = 0; 118 119 measurementNdx < maxNumMeasurements && 120 (measurementNdx < numConsecutiveMeasurementsRequired || 121 floatRelativeMedianAbsoluteDeviation(latestTimes) > relativeMedianAbsoluteDeviationThreshold); 122 123 measurementNdx++) 124 { 125 const deUint64 startTime = deGetMicroseconds(); 126 dummy = dummyComputation(dummy, computationSize); 127 latestTimes[measurementNdx % numConsecutiveMeasurementsRequired] = (deInt64)(deGetMicroseconds() - startTime); 128 } 129 } 130 131 *warmupCPUInternal::g_dummy.m_v = dummy; 132 } 133 134 } // tcu 135