/*-------------------------------------------------------------------------
* 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