| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 3.0 Module |
| * ------------------------------------------------- |
| * |
| * 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 Buffer data upload performance tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3pBufferDataUploadTests.hpp" |
| #include "glsCalibration.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuCPUWarmup.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "gluRenderContext.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluStrUtil.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluObjectWrapper.hpp" |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| #include "deClock.h" |
| #include "deMath.h" |
| #include "deStringUtil.hpp" |
| #include "deRandom.hpp" |
| #include "deMemory.h" |
| #include "deThread.h" |
| #include "deMeta.hpp" |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <limits> |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Performance |
| { |
| namespace |
| { |
| |
| using gls::theilSenSiegelLinearRegression; |
| using gls::LineParametersWithConfidence; |
| using de::meta::EnableIf; |
| using de::meta::Not; |
| |
| static const char* const s_dummyVertexShader = "#version 300 es\n" |
| "in highp vec4 a_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| "}\n"; |
| |
| static const char* const s_dummyFragnentShader = "#version 300 es\n" |
| "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " dEQP_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| static const char* const s_colorVertexShader = "#version 300 es\n" |
| "in highp vec4 a_position;\n" |
| "in highp vec4 a_color;\n" |
| "out highp vec4 v_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_color = a_color;\n" |
| "}\n"; |
| |
| static const char* const s_colorFragmentShader = "#version 300 es\n" |
| "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" |
| "in mediump vec4 v_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " dEQP_FragColor = v_color;\n" |
| "}\n"; |
| |
| struct SingleOperationDuration |
| { |
| deUint64 totalDuration; |
| deUint64 fitResponseDuration; // used for fitting |
| }; |
| |
| struct MapBufferRangeDuration |
| { |
| deUint64 mapDuration; |
| deUint64 unmapDuration; |
| deUint64 writeDuration; |
| deUint64 allocDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct MapBufferRangeDurationNoAlloc |
| { |
| deUint64 mapDuration; |
| deUint64 unmapDuration; |
| deUint64 writeDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct MapBufferRangeFlushDuration |
| { |
| deUint64 mapDuration; |
| deUint64 unmapDuration; |
| deUint64 writeDuration; |
| deUint64 flushDuration; |
| deUint64 allocDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct MapBufferRangeFlushDurationNoAlloc |
| { |
| deUint64 mapDuration; |
| deUint64 unmapDuration; |
| deUint64 writeDuration; |
| deUint64 flushDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct RenderReadDuration |
| { |
| deUint64 renderDuration; |
| deUint64 readDuration; |
| deUint64 renderReadDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct UnrelatedUploadRenderReadDuration |
| { |
| deUint64 renderDuration; |
| deUint64 readDuration; |
| deUint64 renderReadDuration; |
| deUint64 totalDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct UploadRenderReadDuration |
| { |
| deUint64 uploadDuration; |
| deUint64 renderDuration; |
| deUint64 readDuration; |
| deUint64 totalDuration; |
| deUint64 renderReadDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct UploadRenderReadDurationWithUnrelatedUploadSize |
| { |
| deUint64 uploadDuration; |
| deUint64 renderDuration; |
| deUint64 readDuration; |
| deUint64 totalDuration; |
| deUint64 renderReadDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| struct RenderUploadRenderReadDuration |
| { |
| deUint64 firstRenderDuration; |
| deUint64 uploadDuration; |
| deUint64 secondRenderDuration; |
| deUint64 readDuration; |
| deUint64 totalDuration; |
| deUint64 renderReadDuration; |
| |
| deUint64 fitResponseDuration; |
| }; |
| |
| template <typename SampleT> |
| struct UploadSampleResult |
| { |
| typedef SampleT SampleType; |
| |
| int bufferSize; |
| int allocatedSize; |
| int writtenSize; |
| SampleType duration; |
| }; |
| |
| template <typename SampleT> |
| struct RenderSampleResult |
| { |
| typedef SampleT SampleType; |
| |
| int uploadedDataSize; |
| int renderDataSize; |
| int unrelatedDataSize; |
| int numVertices; |
| SampleT duration; |
| }; |
| |
| struct SingleOperationStatistics |
| { |
| float minTime; |
| float maxTime; |
| float medianTime; |
| float min2DecileTime; // !< minimum value in the 2nd decile |
| float max9DecileTime; // !< maximum value in the 9th decile |
| }; |
| |
| struct SingleCallStatistics |
| { |
| SingleOperationStatistics result; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| struct MapCallStatistics |
| { |
| SingleOperationStatistics map; |
| SingleOperationStatistics unmap; |
| SingleOperationStatistics write; |
| SingleOperationStatistics alloc; |
| SingleOperationStatistics result; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| struct MapFlushCallStatistics |
| { |
| SingleOperationStatistics map; |
| SingleOperationStatistics unmap; |
| SingleOperationStatistics write; |
| SingleOperationStatistics flush; |
| SingleOperationStatistics alloc; |
| SingleOperationStatistics result; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| struct RenderReadStatistics |
| { |
| SingleOperationStatistics render; |
| SingleOperationStatistics read; |
| SingleOperationStatistics result; |
| SingleOperationStatistics total; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| struct UploadRenderReadStatistics |
| { |
| SingleOperationStatistics upload; |
| SingleOperationStatistics render; |
| SingleOperationStatistics read; |
| SingleOperationStatistics result; |
| SingleOperationStatistics total; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| struct RenderUploadRenderReadStatistics |
| { |
| SingleOperationStatistics firstRender; |
| SingleOperationStatistics upload; |
| SingleOperationStatistics secondRender; |
| SingleOperationStatistics read; |
| SingleOperationStatistics result; |
| SingleOperationStatistics total; |
| |
| float medianRate; |
| float maxDiffTime; |
| float maxDiff9DecileTime; |
| float medianDiffTime; |
| |
| float maxRelDiffTime; |
| float max9DecileRelDiffTime; |
| float medianRelDiffTime; |
| }; |
| |
| template <typename T> |
| struct SampleTypeTraits |
| { |
| }; |
| |
| template <> |
| struct SampleTypeTraits<SingleOperationDuration> |
| { |
| typedef SingleCallStatistics StatsType; |
| |
| enum { HAS_MAP_STATS = 0 }; |
| enum { HAS_UNMAP_STATS = 0 }; |
| enum { HAS_WRITE_STATS = 0 }; |
| enum { HAS_FLUSH_STATS = 0 }; |
| enum { HAS_ALLOC_STATS = 0 }; |
| enum { LOG_CONTRIBUTIONS = 0 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<MapBufferRangeDuration> |
| { |
| typedef MapCallStatistics StatsType; |
| |
| enum { HAS_MAP_STATS = 1 }; |
| enum { HAS_UNMAP_STATS = 1 }; |
| enum { HAS_WRITE_STATS = 1 }; |
| enum { HAS_FLUSH_STATS = 0 }; |
| enum { HAS_ALLOC_STATS = 1 }; |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<MapBufferRangeDurationNoAlloc> |
| { |
| typedef MapCallStatistics StatsType; |
| |
| enum { HAS_MAP_STATS = 1 }; |
| enum { HAS_UNMAP_STATS = 1 }; |
| enum { HAS_WRITE_STATS = 1 }; |
| enum { HAS_FLUSH_STATS = 0 }; |
| enum { HAS_ALLOC_STATS = 0 }; |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<MapBufferRangeFlushDuration> |
| { |
| typedef MapFlushCallStatistics StatsType; |
| |
| enum { HAS_MAP_STATS = 1 }; |
| enum { HAS_UNMAP_STATS = 1 }; |
| enum { HAS_WRITE_STATS = 1 }; |
| enum { HAS_FLUSH_STATS = 1 }; |
| enum { HAS_ALLOC_STATS = 1 }; |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<MapBufferRangeFlushDurationNoAlloc> |
| { |
| typedef MapFlushCallStatistics StatsType; |
| |
| enum { HAS_MAP_STATS = 1 }; |
| enum { HAS_UNMAP_STATS = 1 }; |
| enum { HAS_WRITE_STATS = 1 }; |
| enum { HAS_FLUSH_STATS = 1 }; |
| enum { HAS_ALLOC_STATS = 0 }; |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<RenderReadDuration> |
| { |
| typedef RenderReadStatistics StatsType; |
| |
| enum { HAS_RENDER_STATS = 1 }; |
| enum { HAS_READ_STATS = 1 }; |
| enum { HAS_UPLOAD_STATS = 0 }; |
| enum { HAS_TOTAL_STATS = 1 }; |
| enum { HAS_FIRST_RENDER_STATS = 0 }; |
| enum { HAS_SECOND_RENDER_STATS = 0 }; |
| |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<UnrelatedUploadRenderReadDuration> |
| { |
| typedef RenderReadStatistics StatsType; |
| |
| enum { HAS_RENDER_STATS = 1 }; |
| enum { HAS_READ_STATS = 1 }; |
| enum { HAS_UPLOAD_STATS = 0 }; |
| enum { HAS_TOTAL_STATS = 1 }; |
| enum { HAS_FIRST_RENDER_STATS = 0 }; |
| enum { HAS_SECOND_RENDER_STATS = 0 }; |
| |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<UploadRenderReadDuration> |
| { |
| typedef UploadRenderReadStatistics StatsType; |
| |
| enum { HAS_RENDER_STATS = 1 }; |
| enum { HAS_READ_STATS = 1 }; |
| enum { HAS_UPLOAD_STATS = 1 }; |
| enum { HAS_TOTAL_STATS = 1 }; |
| enum { HAS_FIRST_RENDER_STATS = 0 }; |
| enum { HAS_SECOND_RENDER_STATS = 0 }; |
| |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| enum { LOG_UNRELATED_UPLOAD_SIZE = 0 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<UploadRenderReadDurationWithUnrelatedUploadSize> |
| { |
| typedef UploadRenderReadStatistics StatsType; |
| |
| enum { HAS_RENDER_STATS = 1 }; |
| enum { HAS_READ_STATS = 1 }; |
| enum { HAS_UPLOAD_STATS = 1 }; |
| enum { HAS_TOTAL_STATS = 1 }; |
| enum { HAS_FIRST_RENDER_STATS = 0 }; |
| enum { HAS_SECOND_RENDER_STATS = 0 }; |
| |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| enum { LOG_UNRELATED_UPLOAD_SIZE = 1 }; |
| }; |
| |
| template <> |
| struct SampleTypeTraits<RenderUploadRenderReadDuration> |
| { |
| typedef RenderUploadRenderReadStatistics StatsType; |
| |
| enum { HAS_RENDER_STATS = 0 }; |
| enum { HAS_READ_STATS = 1 }; |
| enum { HAS_UPLOAD_STATS = 1 }; |
| enum { HAS_TOTAL_STATS = 1 }; |
| enum { HAS_FIRST_RENDER_STATS = 1 }; |
| enum { HAS_SECOND_RENDER_STATS = 1 }; |
| |
| enum { LOG_CONTRIBUTIONS = 1 }; |
| enum { LOG_UNRELATED_UPLOAD_SIZE = 1 }; |
| }; |
| |
| struct UploadSampleAnalyzeResult |
| { |
| float transferRateMedian; |
| float transferRateAtRange; |
| float transferRateAtInfinity; |
| }; |
| |
| struct RenderSampleAnalyzeResult |
| { |
| float renderRateMedian; |
| float renderRateAtRange; |
| float renderRateAtInfinity; |
| }; |
| |
| class UnmapFailureError : public std::exception |
| { |
| public: |
| UnmapFailureError (void) : std::exception() {} |
| }; |
| |
| static std::string getHumanReadableByteSize (int numBytes) |
| { |
| std::ostringstream buf; |
| |
| if (numBytes < 1024) |
| buf << numBytes << " byte(s)"; |
| else if (numBytes < 1024 * 1024) |
| buf << de::floatToString((float)numBytes/1024.0f, 1) << " KiB"; |
| else |
| buf << de::floatToString((float)numBytes/1024.0f/1024.0f, 1) << " MiB"; |
| |
| return buf.str(); |
| } |
| |
| static deUint64 medianTimeMemcpy (void* dst, const void* src, int numBytes) |
| { |
| // Time used by memcpy is assumed to be asymptotically linear |
| |
| // With large numBytes, the probability of context switch or other random |
| // event is high. Apply memcpy in parts and report how much time would |
| // memcpy have used with the median transfer rate. |
| |
| // Less than 1MiB, no need to do anything special |
| if (numBytes < 1048576) |
| { |
| deUint64 startTime; |
| deUint64 endTime; |
| |
| deYield(); |
| |
| startTime = deGetMicroseconds(); |
| deMemcpy(dst, src, numBytes); |
| endTime = deGetMicroseconds(); |
| |
| return endTime - startTime; |
| } |
| else |
| { |
| // Do memcpy in multiple parts |
| |
| const int numSections = 5; |
| const int sectionAlign = 16; |
| |
| int sectionStarts[numSections+1]; |
| int sectionLens[numSections]; |
| deUint64 sectionTimes[numSections]; |
| deUint64 medianTime; |
| deUint64 bestTime = 0; |
| |
| for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx) |
| sectionStarts[sectionNdx] = deAlign32((numBytes * sectionNdx / numSections), sectionAlign); |
| sectionStarts[numSections] = numBytes; |
| |
| for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx) |
| sectionLens[sectionNdx] = sectionStarts[sectionNdx+1] - sectionStarts[sectionNdx]; |
| |
| // Memcpy is usually called after mapbuffer range which may take |
| // a lot of time. To prevent power management from kicking in during |
| // copy, warm up more. |
| { |
| deYield(); |
| tcu::warmupCPU(); |
| deYield(); |
| } |
| |
| for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx) |
| { |
| deUint64 startTime; |
| deUint64 endTime; |
| |
| startTime = deGetMicroseconds(); |
| deMemcpy((deUint8*)dst + sectionStarts[sectionNdx], (const deUint8*)src + sectionStarts[sectionNdx], sectionLens[sectionNdx]); |
| endTime = deGetMicroseconds(); |
| |
| sectionTimes[sectionNdx] = endTime - startTime; |
| |
| if (!bestTime || sectionTimes[sectionNdx] < bestTime) |
| bestTime = sectionTimes[sectionNdx]; |
| |
| // Detect if write takes 50% longer than it should, and warm up if that happened |
| if (sectionNdx != numSections-1 && (float)sectionTimes[sectionNdx] > 1.5f * (float)bestTime) |
| { |
| deYield(); |
| tcu::warmupCPU(); |
| deYield(); |
| } |
| } |
| |
| std::sort(sectionTimes, sectionTimes + numSections); |
| |
| if ((numSections % 2) == 0) |
| medianTime = (sectionTimes[numSections / 2 - 1] + sectionTimes[numSections / 2]) / 2; |
| else |
| medianTime = sectionTimes[numSections / 2]; |
| |
| return medianTime*numSections; |
| } |
| } |
| |
| static float dummyCalculation (float initial, int workSize) |
| { |
| float a = initial; |
| int b = 123; |
| |
| for (int ndx = 0; ndx < workSize; ++ndx) |
| { |
| a = deFloatCos(a + (float)b); |
| b = (b + 63) % 107 + de::abs((int)(a*10.0f)); |
| } |
| |
| return a + (float)b; |
| } |
| |
| static void busyWait (int microseconds) |
| { |
| const deUint64 maxSingleWaitTime = 1000; // 1ms |
| const deUint64 endTime = deGetMicroseconds() + microseconds; |
| float dummy = *tcu::warmupCPUInternal::g_dummy.m_v; |
| int workSize = 500; |
| |
| // exponentially increase work, cap to 1ms |
| while (deGetMicroseconds() < endTime) |
| { |
| const deUint64 startTime = deGetMicroseconds(); |
| deUint64 totalTime; |
| |
| dummy = dummyCalculation(dummy, workSize); |
| |
| totalTime = deGetMicroseconds() - startTime; |
| |
| if (totalTime >= maxSingleWaitTime) |
| break; |
| else |
| workSize *= 2; |
| } |
| |
| // "wait" |
| while (deGetMicroseconds() < endTime) |
| dummy = dummyCalculation(dummy, workSize); |
| |
| *tcu::warmupCPUInternal::g_dummy.m_v = dummy; |
| } |
| |
| // Sample from given values using linear interpolation at a given position as if values were laid to range [0, 1] |
| template <typename T> |
| static float linearSample (const std::vector<T>& values, float position) |
| { |
| DE_ASSERT(position >= 0.0f); |
| DE_ASSERT(position <= 1.0f); |
| |
| const float floatNdx = (float)(values.size() - 1) * position; |
| const int lowerNdx = (int)deFloatFloor(floatNdx); |
| const int higherNdx = lowerNdx + 1; |
| const float interpolationFactor = floatNdx - (float)lowerNdx; |
| |
| DE_ASSERT(lowerNdx >= 0 && lowerNdx < (int)values.size()); |
| DE_ASSERT(higherNdx >= 0 && higherNdx < (int)values.size()); |
| DE_ASSERT(interpolationFactor >= 0 && interpolationFactor < 1.0f); |
| |
| return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor); |
| } |
| |
| template <typename T> |
| SingleOperationStatistics calculateSingleOperationStatistics (const std::vector<T>& samples, deUint64 T::SampleType::*target) |
| { |
| SingleOperationStatistics stats; |
| std::vector<deUint64> values(samples.size()); |
| |
| for (int ndx = 0; ndx < (int)samples.size(); ++ndx) |
| values[ndx] = samples[ndx].duration.*target; |
| |
| std::sort(values.begin(), values.end()); |
| |
| stats.minTime = (float)values.front(); |
| stats.maxTime = (float)values.back(); |
| stats.medianTime = linearSample(values, 0.5f); |
| stats.min2DecileTime = linearSample(values, 0.1f); |
| stats.max9DecileTime = linearSample(values, 0.9f); |
| |
| return stats; |
| } |
| |
| template <typename StatisticsType, typename SampleType> |
| void calculateBasicStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples, int SampleType::*predictor) |
| { |
| std::vector<deUint64> values(samples.size()); |
| |
| for (int ndx = 0; ndx < (int)samples.size(); ++ndx) |
| values[ndx] = samples[ndx].duration.fitResponseDuration; |
| |
| // median rate |
| { |
| std::vector<float> processingRates(samples.size()); |
| |
| for (int ndx = 0; ndx < (int)samples.size(); ++ndx) |
| { |
| const float timeInSeconds = (float)values[ndx] / 1000.0f / 1000.0f; |
| processingRates[ndx] = (float)(samples[ndx].*predictor) / timeInSeconds; |
| } |
| |
| std::sort(processingRates.begin(), processingRates.end()); |
| |
| stats.medianRate = linearSample(processingRates, 0.5f); |
| } |
| |
| // results compared to the approximation |
| { |
| std::vector<float> timeDiffs(samples.size()); |
| |
| for (int ndx = 0; ndx < (int)samples.size(); ++ndx) |
| { |
| const float prediction = (float)(samples[ndx].*predictor) * fit.coefficient + fit.offset; |
| const float actual = (float)values[ndx]; |
| timeDiffs[ndx] = actual - prediction; |
| } |
| std::sort(timeDiffs.begin(), timeDiffs.end()); |
| |
| stats.maxDiffTime = timeDiffs.back(); |
| stats.maxDiff9DecileTime = linearSample(timeDiffs, 0.9f); |
| stats.medianDiffTime = linearSample(timeDiffs, 0.5f); |
| } |
| |
| // relative comparison to the approximation |
| { |
| std::vector<float> relativeDiffs(samples.size()); |
| |
| for (int ndx = 0; ndx < (int)samples.size(); ++ndx) |
| { |
| const float prediction = (float)(samples[ndx].*predictor) * fit.coefficient + fit.offset; |
| const float actual = (float)values[ndx]; |
| |
| // Ignore cases where we predict negative times, or if |
| // ratio would be (nearly) infinite: ignore if predicted |
| // time is less than 1 microsecond |
| if (prediction < 1.0f) |
| relativeDiffs[ndx] = 0.0f; |
| else |
| relativeDiffs[ndx] = (actual - prediction) / prediction; |
| } |
| std::sort(relativeDiffs.begin(), relativeDiffs.end()); |
| |
| stats.maxRelDiffTime = relativeDiffs.back(); |
| stats.max9DecileRelDiffTime = linearSample(relativeDiffs, 0.9f); |
| stats.medianRelDiffTime = linearSample(relativeDiffs, 0.5f); |
| } |
| |
| // values calculated using sorted timings |
| |
| std::sort(values.begin(), values.end()); |
| |
| stats.result.minTime = (float)values.front(); |
| stats.result.maxTime = (float)values.back(); |
| stats.result.medianTime = linearSample(values, 0.5f); |
| stats.result.min2DecileTime = linearSample(values, 0.1f); |
| stats.result.max9DecileTime = linearSample(values, 0.9f); |
| } |
| |
| template <typename StatisticsType, typename SampleType> |
| void calculateBasicTransferStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples) |
| { |
| calculateBasicStatistics(stats, fit, samples, &SampleType::writtenSize); |
| } |
| |
| template <typename StatisticsType, typename SampleType> |
| void calculateBasicRenderStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples) |
| { |
| calculateBasicStatistics(stats, fit, samples, &SampleType::renderDataSize); |
| } |
| |
| static SingleCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) |
| { |
| SingleCallStatistics stats; |
| |
| calculateBasicTransferStatistics(stats, fit, samples); |
| |
| return stats; |
| } |
| |
| static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) |
| { |
| MapCallStatistics stats; |
| |
| calculateBasicTransferStatistics(stats, fit, samples); |
| |
| stats.map = calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::mapDuration); |
| stats.unmap = calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::unmapDuration); |
| stats.write = calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::writeDuration); |
| stats.alloc = calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::allocDuration); |
| |
| return stats; |
| } |
| |
| static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) |
| { |
| MapFlushCallStatistics stats; |
| |
| calculateBasicTransferStatistics(stats, fit, samples); |
| |
| stats.map = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::mapDuration); |
| stats.unmap = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::unmapDuration); |
| stats.write = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::writeDuration); |
| stats.flush = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::flushDuration); |
| stats.alloc = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::allocDuration); |
| |
| return stats; |
| } |
| |
| static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) |
| { |
| MapCallStatistics stats; |
| |
| calculateBasicTransferStatistics(stats, fit, samples); |
| |
| stats.map = calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::mapDuration); |
| stats.unmap = calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::unmapDuration); |
| stats.write = calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::writeDuration); |
| |
| return stats; |
| } |
| |
| static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) |
| { |
| MapFlushCallStatistics stats; |
| |
| calculateBasicTransferStatistics(stats, fit, samples); |
| |
| stats.map = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::mapDuration); |
| stats.unmap = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::unmapDuration); |
| stats.write = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::writeDuration); |
| stats.flush = calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::flushDuration); |
| |
| return stats; |
| } |
| |
| static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) |
| { |
| RenderReadStatistics stats; |
| |
| calculateBasicRenderStatistics(stats, fit, samples); |
| |
| stats.render = calculateSingleOperationStatistics(samples, &RenderReadDuration::renderDuration); |
| stats.read = calculateSingleOperationStatistics(samples, &RenderReadDuration::readDuration); |
| stats.total = calculateSingleOperationStatistics(samples, &RenderReadDuration::totalDuration); |
| |
| return stats; |
| } |
| |
| static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) |
| { |
| RenderReadStatistics stats; |
| |
| calculateBasicRenderStatistics(stats, fit, samples); |
| |
| stats.render = calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::renderDuration); |
| stats.read = calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::readDuration); |
| stats.total = calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::totalDuration); |
| |
| return stats; |
| } |
| |
| static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) |
| { |
| UploadRenderReadStatistics stats; |
| |
| calculateBasicRenderStatistics(stats, fit, samples); |
| |
| stats.upload = calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::uploadDuration); |
| stats.render = calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::renderDuration); |
| stats.read = calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::readDuration); |
| stats.total = calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::totalDuration); |
| |
| return stats; |
| } |
| |
| static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) |
| { |
| UploadRenderReadStatistics stats; |
| |
| calculateBasicRenderStatistics(stats, fit, samples); |
| |
| stats.upload = calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::uploadDuration); |
| stats.render = calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::renderDuration); |
| stats.read = calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::readDuration); |
| stats.total = calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::totalDuration); |
| |
| return stats; |
| } |
| |
| static RenderUploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) |
| { |
| RenderUploadRenderReadStatistics stats; |
| |
| calculateBasicRenderStatistics(stats, fit, samples); |
| |
| stats.firstRender = calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::firstRenderDuration); |
| stats.upload = calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::uploadDuration); |
| stats.secondRender = calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::secondRenderDuration); |
| stats.read = calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::readDuration); |
| stats.total = calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::totalDuration); |
| |
| return stats; |
| } |
| |
| template <typename DurationType> |
| static LineParametersWithConfidence fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) |
| { |
| std::vector<tcu::Vec2> samplePoints; |
| |
| for (int sampleNdx = beginNdx; sampleNdx < endNdx; sampleNdx += step) |
| { |
| tcu::Vec2 point; |
| |
| point.x() = (float)(samples[sampleNdx].writtenSize); |
| point.y() = (float)(samples[sampleNdx].duration.*target); |
| |
| samplePoints.push_back(point); |
| } |
| |
| return theilSenSiegelLinearRegression(samplePoints, 0.6f); |
| } |
| |
| template <typename DurationType> |
| static LineParametersWithConfidence fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration) |
| { |
| std::vector<tcu::Vec2> samplePoints; |
| |
| for (int sampleNdx = beginNdx; sampleNdx < endNdx; sampleNdx += step) |
| { |
| tcu::Vec2 point; |
| |
| point.x() = (float)(samples[sampleNdx].renderDataSize); |
| point.y() = (float)(samples[sampleNdx].duration.*target); |
| |
| samplePoints.push_back(point); |
| } |
| |
| return theilSenSiegelLinearRegression(samplePoints, 0.6f); |
| } |
| |
| template <typename T> |
| static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) |
| { |
| return fitLineToSamples(samples, beginNdx, endNdx, 1, target); |
| } |
| |
| template <typename T> |
| static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration) |
| { |
| return fitLineToSamples(samples, 0, (int)samples.size(), target); |
| } |
| |
| static float getAreaBetweenLines (float xmin, float xmax, float lineAOffset, float lineACoefficient, float lineBOffset, float lineBCoefficient) |
| { |
| const float lineAMin = lineAOffset + lineACoefficient * xmin; |
| const float lineAMax = lineAOffset + lineACoefficient * xmax; |
| const float lineBMin = lineBOffset + lineBCoefficient * xmin; |
| const float lineBMax = lineBOffset + lineBCoefficient * xmax; |
| const bool aOverBAtBegin = (lineAMin > lineBMin); |
| const bool aOverBAtEnd = (lineAMax > lineBMax); |
| |
| if (aOverBAtBegin == aOverBAtEnd) |
| { |
| // lines do not intersect |
| |
| const float midpoint = (xmin + xmax) / 2.0f; |
| const float width = (xmax - xmin); |
| |
| const float lineAHeight = lineAOffset + lineACoefficient * midpoint; |
| const float lineBHeight = lineBOffset + lineBCoefficient * midpoint; |
| |
| return width * de::abs(lineAHeight - lineBHeight); |
| } |
| else |
| { |
| |
| // lines intersect |
| |
| const float approachCoeffient = de::abs(lineACoefficient - lineBCoefficient); |
| const float epsilon = 0.0001f; |
| const float leftHeight = de::abs(lineAMin - lineBMin); |
| const float rightHeight = de::abs(lineAMax - lineBMax); |
| |
| if (approachCoeffient < epsilon) |
| return 0.0f; |
| |
| return (0.5f * leftHeight * (leftHeight / approachCoeffient)) + (0.5f * rightHeight * (rightHeight / approachCoeffient)); |
| } |
| } |
| |
| template <typename T> |
| static float calculateSampleFitLinearity (const std::vector<T>& samples, int T::*predictor) |
| { |
| // Compare the fitted line of first half of the samples to the fitted line of |
| // the second half of the samples. Calculate a AABB that fully contains every |
| // sample's x component and both fit lines in this range. Calculate the ratio |
| // of the area between the lines and the AABB. |
| |
| const float epsilon = 1.e-6f; |
| const int midPoint = (int)samples.size() / 2; |
| const LineParametersWithConfidence startApproximation = fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration); |
| const LineParametersWithConfidence endApproximation = fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration); |
| |
| const float aabbMinX = (float)(samples.front().*predictor); |
| const float aabbMinY = de::min(startApproximation.offset + startApproximation.coefficient*aabbMinX, endApproximation.offset + endApproximation.coefficient*aabbMinX); |
| const float aabbMaxX = (float)(samples.back().*predictor); |
| const float aabbMaxY = de::max(startApproximation.offset + startApproximation.coefficient*aabbMaxX, endApproximation.offset + endApproximation.coefficient*aabbMaxX); |
| |
| const float aabbArea = (aabbMaxX - aabbMinX) * (aabbMaxY - aabbMinY); |
| const float areaBetweenLines = getAreaBetweenLines(aabbMinX, aabbMaxX, startApproximation.offset, startApproximation.coefficient, endApproximation.offset, endApproximation.coefficient); |
| const float errorAreaRatio = (aabbArea < epsilon) ? (1.0f) : (areaBetweenLines / aabbArea); |
| |
| return de::clamp(1.0f - errorAreaRatio, 0.0f, 1.0f); |
| } |
| |
| template <typename DurationType> |
| static float calculateSampleFitLinearity (const std::vector<UploadSampleResult<DurationType> >& samples) |
| { |
| return calculateSampleFitLinearity(samples, &UploadSampleResult<DurationType>::writtenSize); |
| } |
| |
| template <typename DurationType> |
| static float calculateSampleFitLinearity (const std::vector<RenderSampleResult<DurationType> >& samples) |
| { |
| return calculateSampleFitLinearity(samples, &RenderSampleResult<DurationType>::renderDataSize); |
| } |
| |
| template <typename T> |
| static float calculateSampleTemporalStability (const std::vector<T>& samples, int T::*predictor) |
| { |
| // Samples are sampled in the following order: 1) even samples (in random order) 2) odd samples (in random order) |
| // Compare the fitted line of even samples to the fitted line of the odd samples. Calculate a AABB that fully |
| // contains every sample's x component and both fit lines in this range. Calculate the ratio of the area between |
| // the lines and the AABB. |
| |
| const float epsilon = 1.e-6f; |
| const LineParametersWithConfidence evenApproximation = fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); |
| const LineParametersWithConfidence oddApproximation = fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration); |
| |
| const float aabbMinX = (float)(samples.front().*predictor); |
| const float aabbMinY = de::min(evenApproximation.offset + evenApproximation.coefficient*aabbMinX, oddApproximation.offset + oddApproximation.coefficient*aabbMinX); |
| const float aabbMaxX = (float)(samples.back().*predictor); |
| const float aabbMaxY = de::max(evenApproximation.offset + evenApproximation.coefficient*aabbMaxX, oddApproximation.offset + oddApproximation.coefficient*aabbMaxX); |
| |
| const float aabbArea = (aabbMaxX - aabbMinX) * (aabbMaxY - aabbMinY); |
| const float areaBetweenLines = getAreaBetweenLines(aabbMinX, aabbMaxX, evenApproximation.offset, evenApproximation.coefficient, oddApproximation.offset, oddApproximation.coefficient); |
| const float errorAreaRatio = (aabbArea < epsilon) ? (1.0f) : (areaBetweenLines / aabbArea); |
| |
| return de::clamp(1.0f - errorAreaRatio, 0.0f, 1.0f); |
| } |
| |
| template <typename DurationType> |
| static float calculateSampleTemporalStability (const std::vector<UploadSampleResult<DurationType> >& samples) |
| { |
| return calculateSampleTemporalStability(samples, &UploadSampleResult<DurationType>::writtenSize); |
| } |
| |
| template <typename DurationType> |
| static float calculateSampleTemporalStability (const std::vector<RenderSampleResult<DurationType> >& samples) |
| { |
| return calculateSampleTemporalStability(samples, &RenderSampleResult<DurationType>::renderDataSize); |
| } |
| |
| template <typename DurationType> |
| static void bucketizeSamplesUniformly (const std::vector<UploadSampleResult<DurationType> >& samples, std::vector<UploadSampleResult<DurationType> >* buckets, int numBuckets, int& minBufferSize, int& maxBufferSize) |
| { |
| minBufferSize = 0; |
| maxBufferSize = 0; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| DE_ASSERT(samples[sampleNdx].allocatedSize != 0); |
| |
| if (!minBufferSize || samples[sampleNdx].allocatedSize < minBufferSize) |
| minBufferSize = samples[sampleNdx].allocatedSize; |
| if (!maxBufferSize || samples[sampleNdx].allocatedSize > maxBufferSize) |
| maxBufferSize = samples[sampleNdx].allocatedSize; |
| } |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float bucketNdxFloat = (float)(samples[sampleNdx].allocatedSize - minBufferSize) / (float)(maxBufferSize - minBufferSize) * (float)numBuckets; |
| const int bucketNdx = de::clamp((int)deFloatFloor(bucketNdxFloat), 0, numBuckets-1); |
| |
| buckets[bucketNdx].push_back(samples[sampleNdx]); |
| } |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapRangeStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| log << tcu::TestLog::Float("MapRangeMin", "MapRange: Min time", "us", QP_KEY_TAG_TIME, stats.map.minTime) |
| << tcu::TestLog::Float("MapRangeMax", "MapRange: Max time", "us", QP_KEY_TAG_TIME, stats.map.maxTime) |
| << tcu::TestLog::Float("MapRangeMin90", "MapRange: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.map.min2DecileTime) |
| << tcu::TestLog::Float("MapRangeMax90", "MapRange: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.map.max9DecileTime) |
| << tcu::TestLog::Float("MapRangeMedian", "MapRange: Median time", "us", QP_KEY_TAG_TIME, stats.map.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| log << tcu::TestLog::Float("UnmapMin", "Unmap: Min time", "us", QP_KEY_TAG_TIME, stats.unmap.minTime) |
| << tcu::TestLog::Float("UnmapMax", "Unmap: Max time", "us", QP_KEY_TAG_TIME, stats.unmap.maxTime) |
| << tcu::TestLog::Float("UnmapMin90", "Unmap: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.unmap.min2DecileTime) |
| << tcu::TestLog::Float("UnmapMax90", "Unmap: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.unmap.max9DecileTime) |
| << tcu::TestLog::Float("UnmapMedian", "Unmap: Median time", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| log << tcu::TestLog::Float("WriteMin", "Write: Min time", "us", QP_KEY_TAG_TIME, stats.write.minTime) |
| << tcu::TestLog::Float("WriteMax", "Write: Max time", "us", QP_KEY_TAG_TIME, stats.write.maxTime) |
| << tcu::TestLog::Float("WriteMin90", "Write: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.write.min2DecileTime) |
| << tcu::TestLog::Float("WriteMax90", "Write: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.write.max9DecileTime) |
| << tcu::TestLog::Float("WriteMedian", "Write: Median time", "us", QP_KEY_TAG_TIME, stats.write.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| log << tcu::TestLog::Float("FlushMin", "Flush: Min time", "us", QP_KEY_TAG_TIME, stats.flush.minTime) |
| << tcu::TestLog::Float("FlushMax", "Flush: Max time", "us", QP_KEY_TAG_TIME, stats.flush.maxTime) |
| << tcu::TestLog::Float("FlushMin90", "Flush: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.flush.min2DecileTime) |
| << tcu::TestLog::Float("FlushMax90", "Flush: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.flush.max9DecileTime) |
| << tcu::TestLog::Float("FlushMedian", "Flush: Median time", "us", QP_KEY_TAG_TIME, stats.flush.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| log << tcu::TestLog::Float("AllocMin", "Alloc: Min time", "us", QP_KEY_TAG_TIME, stats.alloc.minTime) |
| << tcu::TestLog::Float("AllocMax", "Alloc: Max time", "us", QP_KEY_TAG_TIME, stats.alloc.maxTime) |
| << tcu::TestLog::Float("AllocMin90", "Alloc: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.alloc.min2DecileTime) |
| << tcu::TestLog::Float("AllocMax90", "Alloc: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.alloc.max9DecileTime) |
| << tcu::TestLog::Float("AllocMedian", "Alloc: Median time", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Value>::Type logMapRangeStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Value>::Type logUnmapStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Value>::Type logWriteStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Value>::Type logFlushStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Value>::Type logAllocStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration); |
| log << tcu::TestLog::Float("MapConstantCost", "Map: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("MapLinearCost", "Map: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("MapMedianCost", "Map: Median cost", "us", QP_KEY_TAG_TIME, stats.map.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration); |
| log << tcu::TestLog::Float("UnmapConstantCost", "Unmap: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("UnmapLinearCost", "Unmap: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("UnmapMedianCost", "Unmap: Median cost", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration); |
| log << tcu::TestLog::Float("WriteConstantCost", "Write: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("WriteLinearCost", "Write: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("WriteMedianCost", "Write: Median cost", "us", QP_KEY_TAG_TIME, stats.write.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration); |
| log << tcu::TestLog::Float("FlushConstantCost", "Flush: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("FlushLinearCost", "Flush: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("FlushMedianCost", "Flush: Median cost", "us", QP_KEY_TAG_TIME, stats.flush.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration); |
| log << tcu::TestLog::Float("AllocConstantCost", "Alloc: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("AllocLinearCost", "Alloc: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("AllocMedianCost", "Alloc: Median cost", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration); |
| log << tcu::TestLog::Float("DrawCallConstantCost", "DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("DrawCallLinearCost", "DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("DrawCallMedianCost", "DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.render.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::readDuration); |
| log << tcu::TestLog::Float("ReadConstantCost", "Read: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("ReadLinearCost", "Read: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ReadMedianCost", "Read: Median cost", "us", QP_KEY_TAG_TIME, stats.read.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration); |
| log << tcu::TestLog::Float("UploadConstantCost", "Upload: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("UploadLinearCost", "Upload: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("UploadMedianCost", "Upload: Median cost", "us", QP_KEY_TAG_TIME, stats.upload.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration); |
| log << tcu::TestLog::Float("TotalConstantCost", "Total: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("TotalLinearCost", "Total: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("TotalMedianCost", "Total: Median cost", "us", QP_KEY_TAG_TIME, stats.total.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration); |
| log << tcu::TestLog::Float("FirstDrawCallConstantCost", "First DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("FirstDrawCallLinearCost", "First DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("FirstDrawCallMedianCost", "First DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.firstRender.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration); |
| log << tcu::TestLog::Float("SecondDrawCallConstantCost", "Second DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset) |
| << tcu::TestLog::Float("SecondDrawCallLinearCost", "Second DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("SecondDrawCallMedianCost", "Second DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.secondRender.medianTime); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Value>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Value>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Value>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Value>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Value>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Value>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_READ_STATS>::Value>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Value>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Value>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Value>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| template <typename SampleType> |
| static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Value>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats) |
| { |
| DE_UNREF(log); |
| DE_UNREF(samples); |
| DE_UNREF(stats); |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("WrittenSize", "Written size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("BufferSize", "Buffer size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UploadTime", "Upload time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].writtenSize |
| << samples[sampleNdx].bufferSize |
| << (int)samples[sampleNdx].duration.totalDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("WrittenSize", "Written size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("BufferSize", "Buffer size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("AllocTime", "Alloc time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("MapTime", "Map time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("UnmapTime", "Unmap time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("WriteTime", "Write time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].writtenSize |
| << samples[sampleNdx].bufferSize |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.allocDuration |
| << (int)samples[sampleNdx].duration.mapDuration |
| << (int)samples[sampleNdx].duration.unmapDuration |
| << (int)samples[sampleNdx].duration.writeDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("WrittenSize", "Written size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("BufferSize", "Buffer size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("MapTime", "Map time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("UnmapTime", "Unmap time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("WriteTime", "Write time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].writtenSize |
| << samples[sampleNdx].bufferSize |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.mapDuration |
| << (int)samples[sampleNdx].duration.unmapDuration |
| << (int)samples[sampleNdx].duration.writeDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("WrittenSize", "Written size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("BufferSize", "Buffer size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("AllocTime", "Alloc time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("MapTime", "Map time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("UnmapTime", "Unmap time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("WriteTime", "Write time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FlushTime", "Flush time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].writtenSize |
| << samples[sampleNdx].bufferSize |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.allocDuration |
| << (int)samples[sampleNdx].duration.mapDuration |
| << (int)samples[sampleNdx].duration.unmapDuration |
| << (int)samples[sampleNdx].duration.writeDuration |
| << (int)samples[sampleNdx].duration.flushDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("WrittenSize", "Written size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("BufferSize", "Buffer size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("MapTime", "Map time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("UnmapTime", "Unmap time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("WriteTime", "Write time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FlushTime", "Flush time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].writtenSize |
| << samples[sampleNdx].bufferSize |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.mapDuration |
| << (int)samples[sampleNdx].duration.unmapDuration |
| << (int)samples[sampleNdx].duration.writeDuration |
| << (int)samples[sampleNdx].duration.flushDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("DataSize", "Data processed", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("VertexCount", "Number of vertices", "vertices", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("DrawCallTime", "Draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].renderDataSize |
| << samples[sampleNdx].numVertices |
| << (int)samples[sampleNdx].duration.renderReadDuration |
| << (int)samples[sampleNdx].duration.renderDuration |
| << (int)samples[sampleNdx].duration.readDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("DataSize", "Data processed", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("VertexCount", "Number of vertices", "vertices", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UnrelatedUploadSize", "Unrelated upload size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("DrawCallTime", "Draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].renderDataSize |
| << samples[sampleNdx].numVertices |
| << samples[sampleNdx].unrelatedDataSize |
| << (int)samples[sampleNdx].duration.renderReadDuration |
| << (int)samples[sampleNdx].duration.renderDuration |
| << (int)samples[sampleNdx].duration.readDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("DataSize", "Data processed", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UploadSize", "Data uploaded", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("VertexCount", "Number of vertices", "vertices", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("DrawReadTime", "Draw call and ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("Upload time", "Upload time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("DrawCallTime", "Draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].renderDataSize |
| << samples[sampleNdx].uploadedDataSize |
| << samples[sampleNdx].numVertices |
| << (int)samples[sampleNdx].duration.renderReadDuration |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.uploadDuration |
| << (int)samples[sampleNdx].duration.renderDuration |
| << (int)samples[sampleNdx].duration.readDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("DataSize", "Data processed", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UploadSize", "Data uploaded", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("VertexCount", "Number of vertices", "vertices", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UnrelatedUploadSize", "Unrelated upload size", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("DrawReadTime", "Draw call and ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("Upload time", "Upload time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("DrawCallTime", "Draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].renderDataSize |
| << samples[sampleNdx].uploadedDataSize |
| << samples[sampleNdx].numVertices |
| << samples[sampleNdx].unrelatedDataSize |
| << (int)samples[sampleNdx].duration.renderReadDuration |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.uploadDuration |
| << (int)samples[sampleNdx].duration.renderDuration |
| << (int)samples[sampleNdx].duration.readDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples) |
| { |
| log << tcu::TestLog::SampleList("Samples", "Samples") |
| << tcu::TestLog::SampleInfo |
| << tcu::TestLog::ValueInfo("DataSize", "Data processed", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("UploadSize", "Data uploaded", "bytes", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("VertexCount", "Number of vertices", "vertices", QP_SAMPLE_VALUE_TAG_PREDICTOR) |
| << tcu::TestLog::ValueInfo("DrawReadTime", "Second draw call and ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("TotalTime", "Total time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FirstDrawCallTime", "First draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("Upload time", "Upload time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("SecondDrawCallTime", "Second draw call time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::ValueInfo("FitResidual", "Fit residual", "us", QP_SAMPLE_VALUE_TAG_RESPONSE) |
| << tcu::TestLog::EndSampleInfo; |
| |
| for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx) |
| { |
| const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize); |
| log << tcu::TestLog::Sample |
| << samples[sampleNdx].renderDataSize |
| << samples[sampleNdx].uploadedDataSize |
| << samples[sampleNdx].numVertices |
| << (int)samples[sampleNdx].duration.renderReadDuration |
| << (int)samples[sampleNdx].duration.totalDuration |
| << (int)samples[sampleNdx].duration.firstRenderDuration |
| << (int)samples[sampleNdx].duration.uploadDuration |
| << (int)samples[sampleNdx].duration.secondRenderDuration |
| << (int)samples[sampleNdx].duration.readDuration |
| << fitResidual |
| << tcu::TestLog::EndSample; |
| } |
| |
| log << tcu::TestLog::EndSampleList; |
| } |
| |
| template <typename SampleType> |
| static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, bool logBucketPerformance) |
| { |
| // Assume data is linear with some outliers, fit a line |
| const LineParametersWithConfidence theilSenFitting = fitLineToSamples(samples); |
| const typename SampleTypeTraits<SampleType>::StatsType resultStats = calculateSampleStatistics(theilSenFitting, samples); |
| float approximatedTransferRate; |
| float approximatedTransferRateNoConstant; |
| |
| // Output raw samples |
| { |
| const tcu::ScopedLogSection section(log, "Samples", "Samples"); |
| logSampleList(log, theilSenFitting, samples); |
| } |
| |
| // Calculate results for different ranges |
| if (logBucketPerformance) |
| { |
| const int numBuckets = 4; |
| int minBufferSize = 0; |
| int maxBufferSize = 0; |
| std::vector<UploadSampleResult<SampleType> > buckets[numBuckets]; |
| |
| bucketizeSamplesUniformly(samples, &buckets[0], numBuckets, minBufferSize, maxBufferSize); |
| |
| for (int bucketNdx = 0; bucketNdx < numBuckets; ++bucketNdx) |
| { |
| if (buckets[bucketNdx].empty()) |
| continue; |
| |
| // Print a nice result summary |
| |
| const int bucketRangeMin = minBufferSize + (int)(((float) bucketNdx / (float)numBuckets) * (float)(maxBufferSize - minBufferSize)); |
| const int bucketRangeMax = minBufferSize + (int)(((float)(bucketNdx+1) / (float)numBuckets) * (float)(maxBufferSize - minBufferSize)); |
| const typename SampleTypeTraits<SampleType>::StatsType stats = calculateSampleStatistics(theilSenFitting, buckets[bucketNdx]); |
| const tcu::ScopedLogSection section (log, "BufferSizeRange", std::string("Transfer performance with buffer size in range [").append(getHumanReadableByteSize(bucketRangeMin).append(", ").append(getHumanReadableByteSize(bucketRangeMax).append("]")))); |
| |
| logMapRangeStats<SampleType>(log, stats); |
| logUnmapStats<SampleType>(log, stats); |
| logWriteStats<SampleType>(log, stats); |
| logFlushStats<SampleType>(log, stats); |
| logAllocStats<SampleType>(log, stats); |
| |
| log << tcu::TestLog::Float("Min", "Total: Min time", "us", QP_KEY_TAG_TIME, stats.result.minTime) |
| << tcu::TestLog::Float("Max", "Total: Max time", "us", QP_KEY_TAG_TIME, stats.result.maxTime) |
| << tcu::TestLog::Float("Min90", "Total: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.result.min2DecileTime) |
| << tcu::TestLog::Float("Max90", "Total: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.result.max9DecileTime) |
| << tcu::TestLog::Float("Median", "Total: Median time", "us", QP_KEY_TAG_TIME, stats.result.medianTime) |
| << tcu::TestLog::Float("MedianTransfer", "Median transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, stats.medianRate / 1024.0f / 1024.0f) |
| << tcu::TestLog::Float("MaxDiff", "Max difference to approximated", "us", QP_KEY_TAG_TIME, stats.maxDiffTime) |
| << tcu::TestLog::Float("Max90Diff", "90%-Max difference to approximated", "us", QP_KEY_TAG_TIME, stats.maxDiff9DecileTime) |
| << tcu::TestLog::Float("MedianDiff", "Median difference to approximated", "us", QP_KEY_TAG_TIME, stats.medianDiffTime) |
| << tcu::TestLog::Float("MaxRelDiff", "Max relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.maxRelDiffTime * 100.0f) |
| << tcu::TestLog::Float("Max90RelDiff", "90%-Max relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.max9DecileRelDiffTime * 100.0f) |
| << tcu::TestLog::Float("MedianRelDiff", "Median relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.medianRelDiffTime * 100.0f); |
| } |
| } |
| |
| // Contributions |
| if (SampleTypeTraits<SampleType>::LOG_CONTRIBUTIONS) |
| { |
| const tcu::ScopedLogSection section(log, "Contribution", "Contributions"); |
| |
| logMapContribution(log, samples, resultStats); |
| logUnmapContribution(log, samples, resultStats); |
| logWriteContribution(log, samples, resultStats); |
| logFlushContribution(log, samples, resultStats); |
| logAllocContribution(log, samples, resultStats); |
| } |
| |
| // Print results |
| { |
| const tcu::ScopedLogSection section(log, "Results", "Results"); |
| |
| const int medianBufferSize = (samples.front().bufferSize + samples.back().bufferSize) / 2; |
| const float approximatedTransferTime = (theilSenFitting.offset + theilSenFitting.coefficient * (float)medianBufferSize) / 1000.0f / 1000.0f; |
| const float approximatedTransferTimeNoConstant = (theilSenFitting.coefficient * (float)medianBufferSize) / 1000.0f / 1000.0f; |
| const float sampleLinearity = calculateSampleFitLinearity(samples); |
| const float sampleTemporalStability = calculateSampleTemporalStability(samples); |
| |
| approximatedTransferRateNoConstant = (float)medianBufferSize / approximatedTransferTimeNoConstant; |
| approximatedTransferRate = (float)medianBufferSize / approximatedTransferTime; |
| |
| log << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f) |
| << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f) |
| << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset) |
| << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower) |
| << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper) |
| << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedTransferRate", "Approximated transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRate / 1024.0f / 1024.0f) |
| << tcu::TestLog::Float("ApproximatedTransferRateNoConstant", "Approximated transfer rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRateNoConstant / 1024.0f / 1024.0f) |
| << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime) |
| << tcu::TestLog::Float("SampleMedianTransfer", "Median transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, resultStats.medianRate / 1024.0f / 1024.0f); |
| } |
| |
| // return approximated transfer rate |
| { |
| UploadSampleAnalyzeResult result; |
| |
| result.transferRateMedian = resultStats.medianRate; |
| result.transferRateAtRange = approximatedTransferRate; |
| result.transferRateAtInfinity = approximatedTransferRateNoConstant; |
| |
| return result; |
| } |
| } |
| |
| template <typename SampleType> |
| static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples) |
| { |
| // Assume data is linear with some outliers, fit a line |
| const LineParametersWithConfidence theilSenFitting = fitLineToSamples(samples); |
| const typename SampleTypeTraits<SampleType>::StatsType resultStats = calculateSampleStatistics(theilSenFitting, samples); |
| float approximatedProcessingRate; |
| float approximatedProcessingRateNoConstant; |
| |
| // output raw samples |
| { |
| const tcu::ScopedLogSection section(log, "Samples", "Samples"); |
| logSampleList(log, theilSenFitting, samples); |
| } |
| |
| // Contributions |
| if (SampleTypeTraits<SampleType>::LOG_CONTRIBUTIONS) |
| { |
| const tcu::ScopedLogSection section(log, "Contribution", "Contributions"); |
| |
| logFirstRenderContribution(log, samples, resultStats); |
| logUploadContribution(log, samples, resultStats); |
| logRenderContribution(log, samples, resultStats); |
| logSecondRenderContribution(log, samples, resultStats); |
| logReadContribution(log, samples, resultStats); |
| logTotalContribution(log, samples, resultStats); |
| } |
| |
| // print results |
| { |
| const tcu::ScopedLogSection section(log, "Results", "Results"); |
| |
| const int medianDataSize = (samples.front().renderDataSize + samples.back().renderDataSize) / 2; |
| const float approximatedRenderTime = (theilSenFitting.offset + theilSenFitting.coefficient * (float)medianDataSize) / 1000.0f / 1000.0f; |
| const float approximatedRenderTimeNoConstant = (theilSenFitting.coefficient * (float)medianDataSize) / 1000.0f / 1000.0f; |
| const float sampleLinearity = calculateSampleFitLinearity(samples); |
| const float sampleTemporalStability = calculateSampleTemporalStability(samples); |
| |
| approximatedProcessingRateNoConstant = (float)medianDataSize / approximatedRenderTimeNoConstant; |
| approximatedProcessingRate = (float)medianDataSize / approximatedRenderTime; |
| |
| log << tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f) |
| << tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f) |
| << tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset) |
| << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower) |
| << tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper) |
| << tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f) |
| << tcu::TestLog::Float("ApproximatedProcessRate", "Approximated processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRate / 1024.0f / 1024.0f) |
| << tcu::TestLog::Float("ApproximatedProcessRateNoConstant", "Approximated processing rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRateNoConstant / 1024.0f / 1024.0f) |
| << tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime) |
| << tcu::TestLog::Float("SampleMedianProcess", "Median processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, resultStats.medianRate / 1024.0f / 1024.0f); |
| } |
| |
| // return approximated render rate |
| { |
| RenderSampleAnalyzeResult result; |
| |
| result.renderRateMedian = resultStats.medianRate; |
| result.renderRateAtRange = approximatedProcessingRate; |
| result.renderRateAtInfinity = approximatedProcessingRateNoConstant; |
| |
| return result; |
| } |
| return RenderSampleAnalyzeResult(); |
| } |
| |
| static void generateTwoPassRandomIterationOrder (std::vector<int>& iterationOrder, int numSamples) |
| { |
| de::Random rnd (0xabc); |
| const int midPoint = (numSamples+1) / 2; // !< ceil(m_numSamples / 2) |
| |
| DE_ASSERT((int)iterationOrder.size() == numSamples); |
| |
| // Two "passes" over range, randomize order in both passes |
| // This allows to us detect if iterations are not independent |
| // (first run and later run samples differ significantly?) |
| |
| for (int sampleNdx = 0; sampleNdx < midPoint; ++sampleNdx) |
| iterationOrder[sampleNdx] = sampleNdx * 2; |
| for (int sampleNdx = midPoint; sampleNdx < numSamples; ++sampleNdx) |
| iterationOrder[sampleNdx] = (sampleNdx - midPoint) * 2 + 1; |
| |
| for (int ndx = 0; ndx < midPoint; ++ndx) |
| std::swap(iterationOrder[ndx], iterationOrder[rnd.getInt(0, midPoint - 1)]); |
| for (int ndx = midPoint; ndx < (int)iterationOrder.size(); ++ndx) |
| std::swap(iterationOrder[ndx], iterationOrder[rnd.getInt(midPoint, (int)iterationOrder.size()-1)]); |
| } |
| |
| template <typename SampleType> |
| class BasicBufferCase : public TestCase |
| { |
| public: |
| |
| enum Flags |
| { |
| FLAG_ALLOCATE_LARGER_BUFFER = 0x01, |
| }; |
| BasicBufferCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, int flags); |
| ~BasicBufferCase (void); |
| |
| virtual void init (void); |
| virtual void deinit (void); |
| |
| protected: |
| IterateResult iterate (void); |
| |
| virtual bool runSample (int iteration, UploadSampleResult<SampleType>& sample) = 0; |
| virtual void logAndSetTestResult (const std::vector<UploadSampleResult<SampleType> >& results) = 0; |
| |
| void disableGLWarmup (void); |
| void waitGLResults (void); |
| |
| enum |
| { |
| DUMMY_RENDER_AREA_SIZE = 32 |
| }; |
| |
| glu::ShaderProgram* m_dummyProgram; |
| deInt32 m_dummyProgramPosLoc; |
| deUint32 m_bufferID; |
| |
| const int m_numSamples; |
| const int m_bufferSizeMin; |
| const int m_bufferSizeMax; |
| const bool m_allocateLargerBuffer; |
| |
| private: |
| int m_iteration; |
| std::vector<int> m_iterationOrder; |
| std::vector<UploadSampleResult<SampleType> > m_results; |
| |
| bool m_useGL; |
| int m_bufferRandomizerTimer; |
| }; |
| |
| template <typename SampleType> |
| BasicBufferCase<SampleType>::BasicBufferCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, int flags) |
| : TestCase (context, tcu::NODETYPE_PERFORMANCE, name, desc) |
| , m_dummyProgram (DE_NULL) |
| , m_dummyProgramPosLoc (-1) |
| , m_bufferID (0) |
| , m_numSamples (numSamples) |
| , m_bufferSizeMin (bufferSizeMin) |
| , m_bufferSizeMax (bufferSizeMax) |
| , m_allocateLargerBuffer ((flags & FLAG_ALLOCATE_LARGER_BUFFER) != 0) |
| , m_iteration (0) |
| , m_iterationOrder (numSamples) |
| , m_results (numSamples) |
| , m_useGL (true) |
| , m_bufferRandomizerTimer (0) |
| { |
| // "randomize" iteration order. Deterministic, patternless |
| generateTwoPassRandomIterationOrder(m_iterationOrder, m_numSamples); |
| |
| // choose buffer sizes |
| for (int sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx) |
| { |
| const int rawBufferSize = (int)deFloatFloor((float)bufferSizeMin + (float)(bufferSizeMax - bufferSizeMin) * ((float)(sampleNdx + 1) / (float)m_numSamples)); |
| const int bufferSize = deAlign32(rawBufferSize, 16); |
| const int allocatedBufferSize = deAlign32((m_allocateLargerBuffer) ? ((int)((float)bufferSize * 1.5f)) : (bufferSize), 16); |
| |
| m_results[sampleNdx].bufferSize = bufferSize; |
| m_results[sampleNdx].allocatedSize = allocatedBufferSize; |
| m_results[sampleNdx].writtenSize = -1; |
| } |
| } |
| |
| template <typename SampleType> |
| BasicBufferCase<SampleType>::~BasicBufferCase (void) |
| { |
| deinit(); |
| } |
| |
| template <typename SampleType> |
| void BasicBufferCase<SampleType>::init (void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (!m_useGL) |
| return; |
| |
| // \note Viewport size is not checked, it won't matter if the render target actually is smaller hhan DUMMY_RENDER_AREA_SIZE |
| |
| // dummy shader |
| |
| m_dummyProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_dummyVertexShader) << glu::FragmentSource(s_dummyFragnentShader)); |
| if (!m_dummyProgram->isOk()) |
| { |
| m_testCtx.getLog() << *m_dummyProgram; |
| throw tcu::TestError("failed to build shader program"); |
| } |
| |
| m_dummyProgramPosLoc = gl.getAttribLocation(m_dummyProgram->getProgram(), "a_position"); |
| if (m_dummyProgramPosLoc == -1) |
| throw tcu::TestError("a_position location was -1"); |
| } |
| |
| template <typename SampleType> |
| void BasicBufferCase<SampleType>::deinit (void) |
| { |
| if (m_bufferID) |
| { |
| m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_bufferID); |
| m_bufferID = 0; |
| } |
| |
| delete m_dummyProgram; |
| m_dummyProgram = DE_NULL; |
| } |
| |
| template <typename SampleType> |
| TestCase::IterateResult BasicBufferCase<SampleType>::iterate (void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| static bool buffersWarmedUp = false; |
| |
| static const deUint32 usages[] = |
| { |
| GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, |
| GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, |
| GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY, |
| }; |
| |
| // Allocate some random sized buffers and remove them to |
| // make sure the first samples too have some buffers removed |
| // just before their allocation. This is only needed by the |
| // the first test. |
| |
| if (m_useGL && !buffersWarmedUp) |
| { |
| const int numRandomBuffers = 6; |
| const int numRepeats = 10; |
| const int maxBufferSize = 16777216; |
| const std::vector<deUint8> zeroData (maxBufferSize, 0x00); |
| de::Random rnd (0x1234); |
| deUint32 bufferIDs[numRandomBuffers] = {0}; |
| |
| gl.useProgram(m_dummyProgram->getProgram()); |
| gl.viewport(0, 0, DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE); |
| gl.enableVertexAttribArray(m_dummyProgramPosLoc); |
| |
| for (int ndx = 0; ndx < numRepeats; ++ndx) |
| { |
| // Create buffer and maybe draw from it |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| { |
| const int randomSize = deAlign32(rnd.getInt(1, maxBufferSize), 4*4); |
| const deUint32 usage = usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)]; |
| |
| gl.genBuffers(1, &bufferIDs[randomBufferNdx]); |
| gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]); |
| gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage); |
| |
| if (rnd.getBool()) |
| { |
| gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| gl.drawArrays(GL_POINTS, 0, 1); |
| gl.drawArrays(GL_POINTS, randomSize / (int)sizeof(float[4]) - 1, 1); |
| } |
| } |
| |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]); |
| |
| waitGLResults(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer gen"); |
| |
| m_testCtx.touchWatchdog(); |
| } |
| |
| buffersWarmedUp = true; |
| return CONTINUE; |
| } |
| else if (m_useGL && m_bufferRandomizerTimer++ % 8 == 0) |
| { |
| // Do some random buffer operations to every now and then |
| // to make sure the previous test iterations won't affect |
| // following test runs. |
| |
| const int numRandomBuffers = 3; |
| const int maxBufferSize = 16777216; |
| const std::vector<deUint8> zeroData (maxBufferSize, 0x00); |
| de::Random rnd (0x1234 + 0xabc * m_bufferRandomizerTimer); |
| |
| // BufferData |
| { |
| deUint32 bufferIDs[numRandomBuffers] = {0}; |
| |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| { |
| const int randomSize = deAlign32(rnd.getInt(1, maxBufferSize), 4*4); |
| const deUint32 usage = usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)]; |
| |
| gl.genBuffers(1, &bufferIDs[randomBufferNdx]); |
| gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]); |
| gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage); |
| } |
| |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "buffer ops"); |
| |
| // Do some memory mappings |
| { |
| deUint32 bufferIDs[numRandomBuffers] = {0}; |
| |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| { |
| const int randomSize = deAlign32(rnd.getInt(1, maxBufferSize), 4*4); |
| const deUint32 usage = usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)]; |
| void* ptr; |
| |
| gl.genBuffers(1, &bufferIDs[randomBufferNdx]); |
| gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]); |
| gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage); |
| |
| gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL); |
| gl.drawArrays(GL_POINTS, 0, 1); |
| gl.drawArrays(GL_POINTS, randomSize / (int)sizeof(float[4]) - 1, 1); |
| |
| if (rnd.getBool()) |
| waitGLResults(); |
| |
| ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, randomSize, GL_MAP_WRITE_BIT); |
| if (ptr) |
| { |
| medianTimeMemcpy(ptr, &zeroData[0], randomSize); |
| gl.unmapBuffer(GL_ARRAY_BUFFER); |
| } |
| } |
| |
| for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx) |
| gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]); |
| |
| waitGLResults(); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "buffer maps"); |
| return CONTINUE; |
| } |
| else |
| { |
| const int currentIteration = m_iteration; |
| const int sampleNdx = m_iterationOrder[currentIteration]; |
| const bool sampleRunSuccessful = runSample(currentIteration, m_results[sampleNdx]); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "post runSample()"); |
| |
| // Retry failed samples |
| if (!sampleRunSuccessful) |
| return CONTINUE; |
| |
| if (++m_iteration >= m_numSamples) |
| { |
| logAndSetTestResult(m_results); |
| return STOP; |
| } |
| else |
| return CONTINUE; |
| } |
| } |
| |
| template <typename SampleType> |
| void BasicBufferCase<SampleType>::disableGLWarmup (void) |
| { |
| m_useGL = false; |
| } |
| |
| template <typename SampleType> |
| void BasicBufferCase<SampleType>::waitGLResults (void) |
| { |
| tcu::Surface dummySurface(DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE); |
| glu::readPixels(m_context.getRenderContext(), 0, 0, dummySurface.getAccess()); |
| } |
| |
| template <typename SampleType> |
| class BasicUploadCase : public BasicBufferCase<SampleType> |
| { |
| public: |
| enum CaseType |
| { |
| CASE_NO_BUFFERS = 0, |
| CASE_NEW_BUFFER, |
| CASE_UNSPECIFIED_BUFFER, |
| CASE_SPECIFIED_BUFFER, |
| CASE_USED_BUFFER, |
| CASE_USED_LARGER_BUFFER, |
| |
| CASE_LAST |
| }; |
| |
| enum CaseFlags |
| { |
| FLAG_DONT_LOG_BUFFER_INFO = 0x01, |
| FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT = 0x02, |
| }; |
| |
| enum ResultType |
| { |
| RESULT_MEDIAN_TRANSFER_RATE = 0, |
| RESULT_ASYMPTOTIC_TRANSFER_RATE, |
| }; |
| |
| BasicUploadCase (Context& context, |
| const char* name, |
| const char* desc, |
| int bufferSizeMin, |
| int bufferSizeMax, |
| int numSamples, |
| deUint32 bufferUsage, |
| CaseType caseType, |
| ResultType resultType, |
| int flags = 0); |
| |
| ~BasicUploadCase (void); |
| |
| virtual void init (void); |
| virtual void deinit (void); |
| |
| private: |
| bool runSample (int iteration, UploadSampleResult<SampleType>& sample); |
| void createBuffer (int bufferSize, int iteration); |
| void deleteBuffer (int bufferSize); |
| void useBuffer (int bufferSize); |
| |
| virtual void testBufferUpload (UploadSampleResult<SampleType>& result, int writeSize) = 0; |
| void logAndSetTestResult (const std::vector<UploadSampleResult<SampleType> >& results); |
| |
| deUint32 m_dummyBufferID; |
| |
| protected: |
| const CaseType m_caseType; |
| const ResultType m_resultType; |
| const deUint32 m_bufferUsage; |
| const bool m_logBufferInfo; |
| const bool m_bufferUnspecifiedContent; |
| std::vector<deUint8> m_zeroData; |
| |
| using BasicBufferCase<SampleType>::m_testCtx; |
| using BasicBufferCase<SampleType>::m_context; |
| |
| using BasicBufferCase<SampleType>::DUMMY_RENDER_AREA_SIZE; |
| using BasicBufferCase<SampleType>::m_dummyProgram; |
| using BasicBufferCase<SampleType>::m_dummyProgramPosLoc; |
| using BasicBufferCase<SampleType>::m_bufferID; |
| using BasicBufferCase<SampleType>::m_numSamples; |
| using BasicBufferCase<SampleType>::m_bufferSizeMin; |
| using BasicBufferCase<SampleType>::m_bufferSizeMax; |
| using BasicBufferCase<SampleType>::m_allocateLargerBuffer; |
| }; |
| |
| template <typename SampleType> |
| BasicUploadCase<SampleType>::BasicUploadCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, deUint32 bufferUsage, CaseType caseType, ResultType resultType, int flags) |
| : BasicBufferCase<SampleType> (context, name, desc, bufferSizeMin, bufferSizeMax, numSamples, (caseType == CASE_USED_LARGER_BUFFER) ? (BasicBufferCase<SampleType>::FLAG_ALLOCATE_LARGER_BUFFER) : (0)) |
| , m_dummyBufferID (0) |
| , m_caseType (caseType) |
| , m_resultType (resultType) |
| , m_bufferUsage (bufferUsage) |
| , m_logBufferInfo ((flags & FLAG_DONT_LOG_BUFFER_INFO) == 0) |
| , m_bufferUnspecifiedContent ((flags & FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT) != 0) |
| , m_zeroData () |
| { |
| DE_ASSERT(m_caseType < CASE_LAST); |
| } |
| |
| template <typename SampleType> |
| BasicUploadCase<SampleType>::~BasicUploadCase (void) |
| { |
| deinit(); |
| } |
| |
| template <typename SampleType> |
| void BasicUploadCase<SampleType>::init (void) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| BasicBufferCase<SampleType>::init(); |
| |
| // zero buffer as upload source |
| m_zeroData.resize(m_bufferSizeMax, 0x00); |
| |
| // dummy buffer |
| |
| gl.genBuffers(1, &m_dummyBufferID); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Gen buf"); |
| |
| // log basic info |
| |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Testing performance with " << m_numSamples << " test samples. Sample order is randomized. All samples at even positions (first = 0) are tested before samples at odd positions.\n" |
| << "Buffer sizes are in range [" << getHumanReadableByteSize(m_bufferSizeMin) << ", " << getHumanReadableByteSize(m_bufferSizeMax) << "]." |
| << tcu::TestLog::EndMessage; |
| |
| if (m_logBufferInfo) |
| { |
| switch (m_caseType) |
| { |
| case CASE_NO_BUFFERS: |
| break; |
| |
| case CASE_NEW_BUFFER: |
| m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is generated but not specified (i.e glBufferData() not called)." << tcu::TestLog::EndMessage; |
| break; |
| |
| case CASE_UNSPECIFIED_BUFFER: |
| m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is allocated with glBufferData(NULL)." << tcu::TestLog::EndMessage; |
| break; |
| |
| case CASE_SPECIFIED_BUFFER: |
| m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer contents are specified prior testing with glBufferData(data)." << tcu::TestLog::EndMessage; |
| break; |
| |
| case CASE_USED_BUFFER: |
| m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer has been used in drawing before testing." << tcu::TestLog::EndMessage; |
| break; |
| |
| case CASE_USED_LARGER_BUFFER: |
| m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is larger and has been used in drawing before testing." << tcu::TestLog::EndMessage; |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| } |
| |
| if (m_resultType == RESULT_MEDIAN_TRANSFER_RATE) |
| m_testCtx.getLog() << tcu::TestLog::Message << "Test result is the median transfer rate of the test samples." << tcu::TestLog::EndMessage; |
| else if (m_resultType == RESULT_ASYMPTOTIC_TRANSFER_RATE) |
| m_testCtx.getLog() << tcu::TestLog::Message << "Test result is the asymptotic transfer rate as the buffer size approaches infinity." << tcu::TestLog::EndMessage; |
| else |
| DE_ASSERT(false); |
| } |
| |
| template <typename SampleType> |
| void BasicUploadCase<SampleType>::deinit (void) |
| { |
| if (m_dummyBufferID) |
| { |
| m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dummyBufferID); |
| m_dummyBufferID = 0; |
| } |
| |
| m_zeroData = std::vector<deUint8>(); |
| |
| BasicBufferCase<SampleType>::deinit(); |
| } |
| |
| template <typename SampleType> |
| bool BasicUploadCase<SampleType>::runSample (int iteration, UploadSampleResult<SampleType>& sample) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const int allocatedBufferSize = sample.allocatedSize; |
| const int bufferSize = sample.bufferSize; |
| |
| if (m_caseType != CASE_NO_BUFFERS) |
| createBuffer(iteration, allocatedBufferSize); |
| |
| // warmup CPU before the test to make sure the power management governor |
| // keeps us in the "high performance" mode |
| { |
| deYield(); |
| tcu::warmupCPU(); |
| deYield(); |
| } |
| |
| testBufferUpload(sample, bufferSize); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer upload sample"); |
| |
| if (m_caseType != CASE_NO_BUFFERS) |
| deleteBuffer(bufferSize); |
| |
| return true; |
| } |
| |
| template <typename SampleType> |
| void BasicUploadCase<SampleType>::createBuffer (int iteration, int bufferSize) |
| { |
| DE_ASSERT(!m_bufferID); |
| DE_ASSERT(m_caseType != CASE_NO_BUFFERS); |
| |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| // create buffer |
| |
| if (m_caseType == CASE_NO_BUFFERS) |
| return; |
| |
| // create empty buffer |
| |
| gl.genBuffers(1, &m_bufferID); |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer gen"); |
| |
| if (m_caseType == CASE_NEW_BUFFER) |
| { |
| // upload something else first, this should reduce noise in samples |
| |
| de::Random rng (0xbadc * iteration); |
| const int sizeDelta = rng.getInt(0, 2097140); |
| const int dummyUploadSize = deAlign32(1048576 + sizeDelta, 4*4); // Vary buffer size to make sure it is always reallocated |
| const std::vector<deUint8> dummyData (dummyUploadSize, 0x20); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_dummyBufferID); |
| gl.bufferData(GL_ARRAY_BUFFER, dummyUploadSize, &dummyData[0], m_bufferUsage); |
| |
| // make sure upload won't interfere with the test |
| useBuffer(dummyUploadSize); |
| |
| // don't kill the buffer so that the following upload cannot potentially reuse the buffer |
| |
| return; |
| } |
| |
| // specify it |
| |
| if (m_caseType == CASE_UNSPECIFIED_BUFFER) |
| gl.bufferData(GL_ARRAY_BUFFER, bufferSize, DE_NULL, m_bufferUsage); |
| else |
| { |
| const std::vector<deUint8> dummyData(bufferSize, 0x20); |
| gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &dummyData[0], m_bufferUsage); |
| } |
| |
| if (m_caseType == CASE_UNSPECIFIED_BUFFER || m_caseType == CASE_SPECIFIED_BUFFER) |
| return; |
| |
| // use it and make sure it is uploaded |
| |
| useBuffer(bufferSize); |
| DE_ASSERT(m_caseType == CASE_USED_BUFFER || m_caseType == CASE_USED_LARGER_BUFFER); |
| } |
| |
| template <typename SampleType> |
| void BasicUploadCase<SampleType>::deleteBuffer (int bufferSize) |
| { |
| DE_ASSERT(m_bufferID); |
| DE_ASSERT(m_caseType != CASE_NO_BUFFERS); |
| |
| // render from the buffer to make sure it actually made it to the gpu. This is to |
| // make sure that if the upload actually happens later or is happening right now in |
| // the background, it will not interfere with further test runs |
| |
| // if buffer contains unspecified content, sourcing data from it results in undefined |
| // results, possibly including program termination. Specify all data to prevent such |
| // case from happening |
| |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID); |
| |
| if (m_bufferUnspecifiedContent) |
| { |
| const std::vector<deUint8> dummyData(bufferSize, 0x20); |
| gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &dummyData[0], m_bufferUsage); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "re-specify buffer"); |
| } |
| |
| useBuffer(bufferSize); |
| |
| gl.deleteBuffers(1, &m_bufferID); |
| m_bufferID = 0; |
| } |
| |
| template <typename SampleType> |
| void BasicUploadCase<SampleType>::useBuffer (int bufferSize) |
| { |
| const glw::Functions |