mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1233 lines
46 KiB
1233 lines
46 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#include <sstream> |
|
#include <Corrade/Containers/Pointer.h> |
|
#include <Corrade/TestSuite/Tester.h> |
|
#include <Corrade/TestSuite/Compare/Numeric.h> |
|
#include <Corrade/Utility/DebugStl.h> |
|
#include <Corrade/Utility/ConfigurationGroup.h> |
|
#include <Corrade/Utility/System.h> |
|
|
|
#include "Magnum/DebugTools/FrameProfiler.h" |
|
|
|
namespace Magnum { namespace DebugTools { namespace Test { namespace { |
|
|
|
struct FrameProfilerTest: TestSuite::Tester { |
|
explicit FrameProfilerTest(); |
|
|
|
void defaultConstructed(); |
|
void noMeasurements(); |
|
|
|
void singleFrame(); |
|
void multipleFrames(); |
|
|
|
void enableDisable(); |
|
void reSetup(); |
|
|
|
void copy(); |
|
void move(); |
|
|
|
void frameCountZero(); |
|
void delayZero(); |
|
void delayTooLittleFrames(); |
|
void startStopFrameUnexpected(); |
|
void measurementOutOfRange(); |
|
void frameOutOfRange(); |
|
void dataNotAvailableYet(); |
|
void meanNotAvailableYet(); |
|
|
|
void statistics(); |
|
|
|
#ifdef MAGNUM_TARGET_GL |
|
void gl(); |
|
void glNotEnabled(); |
|
#endif |
|
|
|
void debugUnits(); |
|
#ifdef MAGNUM_TARGET_GL |
|
void debugGLValue(); |
|
void debugGLValues(); |
|
|
|
void configurationGLValue(); |
|
void configurationGLValues(); |
|
#endif |
|
}; |
|
|
|
struct { |
|
const char* name; |
|
bool delayed; |
|
} SingleFrameData[]{ |
|
{"", false}, |
|
{"delayed by 1", true} |
|
}; |
|
|
|
struct { |
|
const char* name; |
|
bool delayed; |
|
UnsignedInt delay; |
|
} MultipleFramesData[]{ |
|
{"", false, 1}, |
|
{"delayed by 1", true, 1}, |
|
{"delayed by 2", true, 2}, |
|
{"delayed by 3", true, 3} |
|
}; |
|
|
|
#ifdef MAGNUM_TARGET_GL |
|
struct { |
|
const char* name; |
|
FrameProfilerGL::Values values; |
|
UnsignedInt measurementCount; |
|
UnsignedInt measurementDelay; |
|
} GLData[]{ |
|
{"empty", {}, 0, 1}, |
|
{"frame time", FrameProfilerGL::Value::FrameTime, 1, 2}, |
|
{"cpu duration", FrameProfilerGL::Value::CpuDuration, 1, 1}, |
|
{"frame time + cpu duration", FrameProfilerGL::Value::FrameTime|FrameProfilerGL::Value::CpuDuration, 2, 2} |
|
}; |
|
#endif |
|
|
|
FrameProfilerTest::FrameProfilerTest() { |
|
addTests({&FrameProfilerTest::defaultConstructed, |
|
&FrameProfilerTest::noMeasurements}); |
|
|
|
addInstancedTests({&FrameProfilerTest::singleFrame}, |
|
Containers::arraySize(SingleFrameData)); |
|
addInstancedTests({&FrameProfilerTest::multipleFrames}, |
|
Containers::arraySize(MultipleFramesData)); |
|
|
|
addTests({&FrameProfilerTest::enableDisable, |
|
&FrameProfilerTest::reSetup, |
|
|
|
&FrameProfilerTest::copy, |
|
&FrameProfilerTest::move, |
|
|
|
&FrameProfilerTest::frameCountZero, |
|
&FrameProfilerTest::delayZero, |
|
&FrameProfilerTest::delayTooLittleFrames, |
|
&FrameProfilerTest::startStopFrameUnexpected, |
|
&FrameProfilerTest::measurementOutOfRange, |
|
&FrameProfilerTest::frameOutOfRange, |
|
&FrameProfilerTest::dataNotAvailableYet, |
|
&FrameProfilerTest::meanNotAvailableYet, |
|
|
|
&FrameProfilerTest::statistics}); |
|
|
|
#ifdef MAGNUM_TARGET_GL |
|
addInstancedTests({&FrameProfilerTest::gl}, |
|
Containers::arraySize(GLData)); |
|
#endif |
|
|
|
addTests({ |
|
#ifdef MAGNUM_TARGET_GL |
|
&FrameProfilerTest::glNotEnabled, |
|
#endif |
|
|
|
&FrameProfilerTest::debugUnits, |
|
#ifdef MAGNUM_TARGET_GL |
|
&FrameProfilerTest::debugGLValue, |
|
&FrameProfilerTest::debugGLValues, |
|
|
|
&FrameProfilerTest::configurationGLValue, |
|
&FrameProfilerTest::configurationGLValues |
|
#endif |
|
}); |
|
} |
|
|
|
void FrameProfilerTest::defaultConstructed() { |
|
FrameProfiler profiler; |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementCount(), 0); |
|
CORRADE_COMPARE(profiler.statistics(), "Last 0 frames:"); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 1); |
|
|
|
/* Shouldn't crash on any silly division by zero even when called a second |
|
time */ |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 2); |
|
} |
|
|
|
void FrameProfilerTest::noMeasurements() { |
|
FrameProfiler profiler{{}, 3}; |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementCount(), 0); |
|
CORRADE_COMPARE(profiler.statistics(), "Last 0 frames:"); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 1); |
|
|
|
/* Shouldn't crash on any silly division by zero even after a wraparound */ |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 2); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 4); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 5); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 6); |
|
} |
|
|
|
void FrameProfilerTest::singleFrame() { |
|
auto&& data = SingleFrameData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
UnsignedLong time = 0, memory = 50; |
|
FrameProfiler profiler; |
|
if(!data.delayed) { |
|
profiler.setup({ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, |
|
[](void* state) { |
|
*static_cast<UnsignedLong*>(state) += 15; |
|
}, |
|
[](void* state) { |
|
return *static_cast<UnsignedLong*>(state) - 15; |
|
}, &time}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, |
|
[](void* state) { |
|
*static_cast<UnsignedLong*>(state) *= 2; |
|
}, |
|
[](void* state) { |
|
return *static_cast<UnsignedLong*>(state) - 100; |
|
}, &memory}, |
|
FrameProfiler::Measurement{ |
|
"Constant", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{100000}; |
|
}, nullptr} |
|
}, 1); |
|
} else { |
|
profiler.setup({ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, 1, |
|
[](void* state, UnsignedInt current) { |
|
CORRADE_COMPARE(current, 0); |
|
static_cast<UnsignedLong*>(state)[current] += 30; |
|
}, |
|
[](void* state, UnsignedInt current) { |
|
CORRADE_COMPARE(current, 0); |
|
static_cast<UnsignedLong*>(state)[current] -= 15; |
|
}, |
|
[](void* state, UnsignedInt previous, UnsignedInt current) { |
|
CORRADE_COMPARE(previous, 0); |
|
CORRADE_COMPARE(current, 0); |
|
return static_cast<UnsignedLong*>(state)[previous] - 15; |
|
}, &time}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, 1, |
|
[](void* state, UnsignedInt current) { |
|
CORRADE_COMPARE(current, 0); |
|
static_cast<UnsignedLong*>(state)[current] *= 4; |
|
}, |
|
[](void* state, UnsignedInt current) { |
|
CORRADE_COMPARE(current, 0); |
|
static_cast<UnsignedLong*>(state)[current] /= 2; |
|
}, |
|
[](void* state, UnsignedInt previous, UnsignedInt current) { |
|
CORRADE_COMPARE(previous, 0); |
|
CORRADE_COMPARE(current, 0); |
|
return static_cast<UnsignedLong*>(state)[previous] - 100; |
|
}, &memory}, |
|
FrameProfiler::Measurement{ |
|
"Constant", FrameProfiler::Units::Count, 1, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { |
|
return UnsignedLong{100000}; |
|
}, nullptr} |
|
}, 1); |
|
} |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementCount(), 3); |
|
|
|
CORRADE_COMPARE(profiler.measurementName(0), "Lag"); |
|
CORRADE_COMPARE(profiler.measurementUnits(0), FrameProfiler::Units::Nanoseconds); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 1); |
|
|
|
CORRADE_COMPARE(profiler.measurementName(1), "Bloat"); |
|
CORRADE_COMPARE(profiler.measurementUnits(1), FrameProfiler::Units::Bytes); |
|
CORRADE_COMPARE(profiler.measurementDelay(1), 1); |
|
|
|
CORRADE_COMPARE(profiler.measurementName(2), "Constant"); |
|
CORRADE_COMPARE(profiler.measurementUnits(2), FrameProfiler::Units::Count); |
|
CORRADE_COMPARE(profiler.measurementDelay(2), 1); |
|
|
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(1)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(2)); |
|
|
|
profiler.beginFrame(); |
|
CORRADE_COMPARE(time, data.delayed ? 30 : 15); |
|
CORRADE_COMPARE(memory, data.delayed ? 200 : 100); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(1)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(2)); |
|
|
|
profiler.endFrame(); |
|
CORRADE_COMPARE(time, 15); |
|
CORRADE_COMPARE(memory, 100); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 1); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(1)); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(2)); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 0.0); |
|
CORRADE_COMPARE(profiler.measurementMean(1), 0.0); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(time, 30); |
|
CORRADE_COMPARE(memory, 200); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 2); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 15); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 100); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 15.0); |
|
CORRADE_COMPARE(profiler.measurementMean(1), 100.0); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(time, 45); |
|
CORRADE_COMPARE(memory, 400); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 30); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 300); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 30.0); |
|
CORRADE_COMPARE(profiler.measurementMean(1), 300.0); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(time, 60); |
|
CORRADE_COMPARE(memory, 800); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 45); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 700); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 45.0); |
|
CORRADE_COMPARE(profiler.measurementMean(1), 700.0); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
} |
|
|
|
void FrameProfilerTest::multipleFrames() { |
|
auto&& data = MultipleFramesData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct State { |
|
UnsignedLong currentTime, currentMemory; |
|
UnsignedLong time[3]; |
|
UnsignedLong memory[3]; |
|
UnsignedInt delay; |
|
} state {0, 50, {0, 0, 0}, {50, 0, 0}, data.delay}; |
|
FrameProfiler profiler; |
|
if(!data.delayed) { |
|
profiler.setup({ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, |
|
[](void* state) { |
|
*static_cast<UnsignedLong*>(state) += 15; |
|
}, |
|
[](void* state) { |
|
return *static_cast<UnsignedLong*>(state) - 15; |
|
}, &state.time[0]}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, |
|
[](void* state) { |
|
*static_cast<UnsignedLong*>(state) *= 2; |
|
}, |
|
[](void* state) { |
|
return *static_cast<UnsignedLong*>(state) - 100; |
|
}, &state.memory[0]}, |
|
FrameProfiler::Measurement{ |
|
"Constant", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{100000}; |
|
}, nullptr} |
|
}, 3); |
|
} else { |
|
profiler.setup({ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, data.delay, |
|
[](void* state, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
s.time[current] = (s.currentTime += 15) + 15; |
|
}, |
|
[](void* state, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
s.time[current] -= 15; |
|
}, |
|
[](void* state, UnsignedInt previous, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(previous, s.delay, TestSuite::Compare::Less); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
CORRADE_VERIFY(current + 1 == previous || (current == s.delay - 1 && previous == 0)); |
|
return s.time[previous] - 15; |
|
}, &state}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, data.delay, |
|
[](void* state, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
s.memory[current] = (s.currentMemory *= 2)*2; |
|
}, |
|
[](void* state, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
s.memory[current] /= 2; |
|
}, |
|
[](void* state, UnsignedInt previous, UnsignedInt current) { |
|
auto& s = *static_cast<State*>(state); |
|
CORRADE_COMPARE_AS(previous, s.delay, TestSuite::Compare::Less); |
|
CORRADE_COMPARE_AS(current, s.delay, TestSuite::Compare::Less); |
|
CORRADE_VERIFY(current + 1 == previous || (current == s.delay - 1 && previous == 0)); |
|
return s.memory[previous] - 100; |
|
}, &state}, |
|
FrameProfiler::Measurement{ |
|
"Undelayed constant", FrameProfiler::Units::Count, 1, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { |
|
return UnsignedLong{100000}; |
|
}, nullptr} |
|
}, 3); |
|
} |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), data.delay); |
|
CORRADE_COMPARE(profiler.measurementDelay(1), data.delay); |
|
CORRADE_COMPARE(profiler.measurementDelay(2), 1); |
|
|
|
for(std::size_t i = 0; i != data.delay - 1; ++i) { |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[i], 15*(i + 1)); |
|
CORRADE_COMPARE(state.memory[i], 100*(i + 1)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(1)); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(2)); |
|
} |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[0 % data.delay], 15); |
|
CORRADE_COMPARE(state.memory[0 % data.delay], 100); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(1)); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(2)); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 0.0); |
|
CORRADE_COMPARE(profiler.measurementMean(1), 0.0); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[1 % data.delay], 30); |
|
CORRADE_COMPARE(state.memory[1 % data.delay], 200); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 1 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(0, 1), 15); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(1, 1), 100); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 1), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), (15.0 + 0.0)/2); |
|
CORRADE_COMPARE(profiler.measurementMean(1), (100.0 + 0.0)/2); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[2 % data.delay], 45); |
|
CORRADE_COMPARE(state.memory[2 % data.delay], 400); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 2 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(0, 1), 15); |
|
CORRADE_COMPARE(profiler.measurementData(0, 2), 30); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 0); |
|
CORRADE_COMPARE(profiler.measurementData(1, 1), 100); |
|
CORRADE_COMPARE(profiler.measurementData(1, 2), 300); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 1), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 2), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), (30.0 + 15.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(1), (300.0 + 100.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
/* At this point it wraps around and should be evicting old values from the |
|
moving average */ |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[3 % data.delay], 60); |
|
CORRADE_COMPARE(state.memory[3 % data.delay], 800); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 15); |
|
CORRADE_COMPARE(profiler.measurementData(0, 1), 30); |
|
CORRADE_COMPARE(profiler.measurementData(0, 2), 45); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 100); |
|
CORRADE_COMPARE(profiler.measurementData(1, 1), 300); |
|
CORRADE_COMPARE(profiler.measurementData(1, 2), 700); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 1), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 2), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), (45.0 + 30.0 + 15.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(1), (700.0 + 300.0 + 100.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[4 % data.delay], 75); |
|
CORRADE_COMPARE(state.memory[4 % data.delay], 1600); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 4 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 30); |
|
CORRADE_COMPARE(profiler.measurementData(0, 1), 45); |
|
CORRADE_COMPARE(profiler.measurementData(0, 2), 60); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 300); |
|
CORRADE_COMPARE(profiler.measurementData(1, 1), 700); |
|
CORRADE_COMPARE(profiler.measurementData(1, 2), 1500); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 1), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 2), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), (60 + 45.0 + 30.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(1), (1500.0 + 700.0 + 300.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(state.time[5 % data.delay], 90); |
|
CORRADE_COMPARE(state.memory[5 % data.delay], 3200); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 5 + data.delay); |
|
CORRADE_COMPARE(profiler.measurementData(0, 0), 45); |
|
CORRADE_COMPARE(profiler.measurementData(0, 1), 60); |
|
CORRADE_COMPARE(profiler.measurementData(0, 2), 75); |
|
CORRADE_COMPARE(profiler.measurementData(1, 0), 700); |
|
CORRADE_COMPARE(profiler.measurementData(1, 1), 1500); |
|
CORRADE_COMPARE(profiler.measurementData(1, 2), 3100); |
|
CORRADE_COMPARE(profiler.measurementData(2, 0), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 1), 100000); |
|
CORRADE_COMPARE(profiler.measurementData(2, 2), 100000); |
|
CORRADE_COMPARE(profiler.measurementMean(0), (75.0 + 60.0 + 45.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(1), (3100.0 + 1500.0 + 700.0)/3); |
|
CORRADE_COMPARE(profiler.measurementMean(2), 100000.0); |
|
} |
|
|
|
void FrameProfilerTest::enableDisable() { |
|
UnsignedLong i = 15; |
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 2, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void* state, UnsignedInt, UnsignedInt) { |
|
return (*static_cast<UnsignedLong*>(state))++; |
|
}, &i}, |
|
}, 5}; |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measurementCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 2); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 15.5); |
|
|
|
/* It should only freeze everything, not wipe out any data */ |
|
profiler.disable(); |
|
CORRADE_COMPARE(profiler.measurementCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 2); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 15.5); |
|
|
|
/* These are a no-op now */ |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
CORRADE_COMPARE(profiler.measurementCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 2); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
CORRADE_COMPARE(profiler.measurementMean(0), 15.5); |
|
|
|
/* Enabling should reset the data to have a clean slate, but not the |
|
measurements */ |
|
profiler.enable(); |
|
CORRADE_COMPARE(profiler.measurementCount(), 1); |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 5); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 2); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
|
|
/* Even though there was no call to endFrame() before, reset() should make |
|
beginFrame() expected again */ |
|
i = 0; |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measurementCount(), 1); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 3); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 2); |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(0)); |
|
/* The per-measurement moving sum should be reset by enable() as well, so |
|
the 15s from before won't contribute to the mean anymore */ |
|
CORRADE_COMPARE(profiler.measurementMean(0), 0.5); |
|
} |
|
|
|
void FrameProfilerTest::reSetup() { |
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 3, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { return UnsignedLong{}; }, nullptr}, |
|
}, 5}; |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
|
|
/* Setup should replace everything */ |
|
profiler.setup({ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, |
|
[](void*) {}, |
|
[](void*) { return UnsignedLong{}; }, |
|
nullptr}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, |
|
[](void*) {}, |
|
[](void*) { return UnsignedLong{}; }, |
|
nullptr}, |
|
}, 10); |
|
CORRADE_COMPARE(profiler.measurementCount(), 2); |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 10); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 0); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 1); |
|
CORRADE_COMPARE(profiler.measurementDelay(1), 1); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(1)); |
|
|
|
/* Even though there was no call to endFrame() before, setup() should make |
|
beginFrame() expected again */ |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
} |
|
|
|
void FrameProfilerTest::copy() { |
|
CORRADE_VERIFY(!std::is_copy_constructible<FrameProfiler>{}); |
|
CORRADE_VERIFY(!std::is_copy_assignable<FrameProfiler>{}); |
|
} |
|
|
|
void FrameProfilerTest::move() { |
|
/* Have two state variables, one in a subclass, one outside. On move the |
|
pointer to a subclass should get patched but the outside not */ |
|
|
|
UnsignedLong i = 15; |
|
struct MyProfiler: FrameProfiler { |
|
UnsignedLong j = 30; |
|
} a; |
|
a.setup({ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void* state) { |
|
return (*static_cast<UnsignedLong*>(state))++; |
|
}, &i}, |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 2, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void* state, UnsignedInt, UnsignedInt) { |
|
return static_cast<MyProfiler*>(state)->j++; |
|
}, &a}, |
|
}, 5); |
|
|
|
/* Move construction */ |
|
MyProfiler b{Utility::move(a)}; |
|
a.j = 100; /* This shouldn't affect b's measurements anymore */ |
|
b.beginFrame(); |
|
b.endFrame(); |
|
b.beginFrame(); |
|
b.endFrame(); |
|
b.beginFrame(); |
|
b.endFrame(); |
|
CORRADE_COMPARE(b.measurementCount(), 2); |
|
CORRADE_COMPARE(b.measuredFrameCount(), 3); |
|
CORRADE_COMPARE(b.measurementDelay(0), 1); |
|
CORRADE_COMPARE(b.measurementDelay(1), 2); |
|
CORRADE_COMPARE(b.measurementMean(0), 16.0); |
|
CORRADE_COMPARE(b.measurementMean(1), 30.5); |
|
|
|
/* Another fully populated instance */ |
|
UnsignedLong k = 45; |
|
MyProfiler c; |
|
c.j = 60; |
|
c.setup({ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void* state) { |
|
return (*static_cast<UnsignedLong*>(state))++; |
|
}, &k}, |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 3, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void* state, UnsignedInt, UnsignedInt) { |
|
return static_cast<MyProfiler*>(state)->j++; |
|
}, &c}, |
|
}, 5); |
|
c.beginFrame(); |
|
c.endFrame(); |
|
c.beginFrame(); |
|
c.endFrame(); |
|
c.beginFrame(); |
|
c.endFrame(); |
|
c.beginFrame(); |
|
c.endFrame(); |
|
CORRADE_COMPARE(c.measurementCount(), 2); |
|
CORRADE_COMPARE(c.measuredFrameCount(), 4); |
|
CORRADE_COMPARE(c.measurementDelay(0), 1); |
|
CORRADE_COMPARE(c.measurementDelay(1), 3); |
|
CORRADE_COMPARE(c.measurementMean(0), 46.5); |
|
CORRADE_COMPARE(c.measurementMean(1), 60.5); |
|
|
|
/* Move assignment */ |
|
CORRADE_COMPARE(c.j, 62); |
|
c = Utility::move(b); |
|
b.j = 62; /* Utility::move() didn't swap this one, so we do; this shouldn't |
|
affect c's measurements anymore */ |
|
c.beginFrame(); |
|
c.endFrame(); |
|
c.beginFrame(); |
|
c.endFrame(); |
|
CORRADE_COMPARE(c.measurementCount(), 2); |
|
CORRADE_COMPARE(c.measuredFrameCount(), 5); |
|
CORRADE_COMPARE(c.measurementDelay(0), 1); |
|
CORRADE_COMPARE(c.measurementDelay(1), 2); |
|
CORRADE_COMPARE(c.measurementMean(0), 17.0); |
|
CORRADE_COMPARE(c.measurementMean(1), 31.5); |
|
|
|
/* Calling these on the swapped instance should affect only itself */ |
|
b.beginFrame(); |
|
b.endFrame(); |
|
CORRADE_COMPARE(b.measurementMean(0), 47.0); /* originally c */ |
|
CORRADE_COMPARE(b.measurementMean(1), 61.0); /* originally c */ |
|
CORRADE_COMPARE(c.measurementCount(), 2); |
|
CORRADE_COMPARE(c.measuredFrameCount(), 5); |
|
CORRADE_COMPARE(c.measurementDelay(0), 1); |
|
CORRADE_COMPARE(c.measurementDelay(1), 2); |
|
CORRADE_COMPARE(c.measurementMean(0), 17.0); |
|
CORRADE_COMPARE(c.measurementMean(1), 31.5); |
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<FrameProfiler>::value); |
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<FrameProfiler>::value); |
|
} |
|
|
|
void FrameProfilerTest::delayZero() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 0, |
|
nullptr, nullptr, nullptr, nullptr}; |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfiler::Measurement: delay can't be zero\n"); |
|
} |
|
|
|
void FrameProfilerTest::frameCountZero() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
FrameProfiler{{}, 0}; |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfiler::setup(): max frame count can't be zero\n"); |
|
} |
|
|
|
void FrameProfilerTest::delayTooLittleFrames() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 3, |
|
nullptr, nullptr, nullptr, nullptr} |
|
}, 2}; |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfiler::setup(): max delay 3 is larger than max frame count 2\n"); |
|
} |
|
|
|
void FrameProfilerTest::startStopFrameUnexpected() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfiler profiler; |
|
|
|
std::ostringstream out; |
|
{ |
|
Error redirectError{&out}; |
|
profiler.endFrame(); |
|
} |
|
profiler.beginFrame(); /* this is not an error */ |
|
{ |
|
Error redirectError{&out}; |
|
profiler.beginFrame(); |
|
} |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::endFrame(): expected begin of frame\n" |
|
"DebugTools::FrameProfiler::beginFrame(): expected end of frame\n"); |
|
} |
|
|
|
void FrameProfilerTest::measurementOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, |
|
nullptr, nullptr, nullptr}, |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, |
|
nullptr, nullptr, nullptr} |
|
}, 1}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementName(2); |
|
profiler.measurementUnits(2); |
|
profiler.measurementDelay(2); |
|
profiler.measurementData(2, 0); |
|
profiler.measurementMean(2); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementName(): index 2 out of range for 2 measurements\n" |
|
"DebugTools::FrameProfiler::measurementUnits(): index 2 out of range for 2 measurements\n" |
|
"DebugTools::FrameProfiler::measurementDelay(): index 2 out of range for 2 measurements\n" |
|
"DebugTools::FrameProfiler::measurementData(): index 2 out of range for 2 measurements\n" |
|
"DebugTools::FrameProfiler::measurementMean(): index 2 out of range for 2 measurements\n"); |
|
} |
|
|
|
void FrameProfilerTest::frameOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void*) { return UnsignedLong{}; }, nullptr}, |
|
}, 3}; |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementData(0, 3); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementData(): frame 3 out of range for max 3 frames\n"); |
|
} |
|
|
|
void FrameProfilerTest::dataNotAvailableYet() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 3, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { return UnsignedLong{}; }, nullptr}, |
|
}, 5}; |
|
|
|
/* Empty state */ |
|
{ |
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementData(0, 0); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementData(): frame 0 of measurement 0 not available yet (delay 3, 0 frames measured so far)\n"); |
|
} |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
/* No wraparound yet */ |
|
{ |
|
profiler.measurementData(0, 0); |
|
profiler.measurementData(0, 1); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementData(0, 2); |
|
profiler.measurementData(0, 3); |
|
profiler.measurementData(0, 4); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementData(): frame 2 of measurement 0 not available yet (delay 3, 4 frames measured so far)\n" |
|
"DebugTools::FrameProfiler::measurementData(): frame 3 of measurement 0 not available yet (delay 3, 4 frames measured so far)\n" |
|
"DebugTools::FrameProfiler::measurementData(): frame 4 of measurement 0 not available yet (delay 3, 4 frames measured so far)\n"); |
|
} |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
/* Wraparound, one last measurement missing */ |
|
{ |
|
profiler.measurementData(0, 0); |
|
profiler.measurementData(0, 1); |
|
profiler.measurementData(0, 2); |
|
profiler.measurementData(0, 3); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementData(0, 4); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementData(): frame 4 of measurement 0 not available yet (delay 3, 6 frames measured so far)\n"); |
|
} |
|
} |
|
|
|
void FrameProfilerTest::meanNotAvailableYet() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{"", FrameProfiler::Units::Count, 3, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { return UnsignedLong{}; }, nullptr}, |
|
}, 5}; |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
CORRADE_COMPARE(profiler.measurementDelay(0), 3); |
|
CORRADE_COMPARE(profiler.measuredFrameCount(), 1); |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(0)); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.measurementMean(0); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfiler::measurementMean(): measurement data available after 2 more frames\n"); |
|
} |
|
|
|
void FrameProfilerTest::statistics() { |
|
UnsignedLong time = 0; |
|
FrameProfiler profiler{{ |
|
FrameProfiler::Measurement{ |
|
"Lag", FrameProfiler::Units::Nanoseconds, 2, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void* state, UnsignedInt, UnsignedInt) { |
|
return *static_cast<UnsignedLong*>(state) += 15; |
|
}, &time}, |
|
FrameProfiler::Measurement{ |
|
"Bloat", FrameProfiler::Units::Bytes, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{1007300*1024*1024ull}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"Age", FrameProfiler::Units::Nanoseconds, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{273*1000*1000}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"GC", FrameProfiler::Units::Nanoseconds, 3, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt) {}, |
|
[](void*, UnsignedInt, UnsignedInt) { |
|
return UnsignedLong{52660}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"Optimizations", FrameProfiler::Units::Count, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{0}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"Frame time", FrameProfiler::Units::Nanoseconds, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{1000*1000*1000ull}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"Sanity ratio", FrameProfiler::Units::RatioThousandths, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{855}; |
|
}, nullptr}, |
|
FrameProfiler::Measurement{ |
|
"CPU usage", FrameProfiler::Units::PercentageThousandths, |
|
[](void*) {}, |
|
[](void*) { |
|
return UnsignedLong{98655}; |
|
}, nullptr} |
|
}, 3}; |
|
|
|
CORRADE_COMPARE(profiler.statistics(), |
|
"Last 0 frames:\n" |
|
" Lag: -.-- s\n" |
|
" Bloat: -.-- B\n" |
|
" Age: -.-- s\n" |
|
" GC: -.-- s\n" |
|
" Optimizations: -.--\n" |
|
" Frame time: -.-- s\n" |
|
" Sanity ratio: -.--\n" |
|
" CPU usage: -.-- %"); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
CORRADE_COMPARE(profiler.statistics(), |
|
"Last 1 frames:\n" |
|
" Lag: -.-- s\n" |
|
" Bloat: 983.69 GB\n" |
|
" Age: 273.00 ms\n" |
|
" GC: -.-- s\n" |
|
" Optimizations: 0.00\n" |
|
" Frame time: 1.00 s\n" |
|
" Sanity ratio: 0.85\n" |
|
" CPU usage: 98.66 %"); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
CORRADE_COMPARE(profiler.statistics(), |
|
"Last 3 frames:\n" |
|
" Lag: 60.00 ns\n" |
|
" Bloat: 983.69 GB\n" |
|
" Age: 273.00 ms\n" |
|
" GC: 52.66 µs\n" |
|
" Optimizations: 0.00\n" |
|
" Frame time: 1.00 s\n" |
|
" Sanity ratio: 0.85\n" |
|
" CPU usage: 98.66 %"); |
|
|
|
/* Disabling should print the last known state */ |
|
profiler.disable(); |
|
CORRADE_COMPARE(profiler.statistics(), |
|
"Last 3 frames:\n" |
|
" Lag: 60.00 ns\n" |
|
" Bloat: 983.69 GB\n" |
|
" Age: 273.00 ms\n" |
|
" GC: 52.66 µs\n" |
|
" Optimizations: 0.00\n" |
|
" Frame time: 1.00 s\n" |
|
" Sanity ratio: 0.85\n" |
|
" CPU usage: 98.66 %"); |
|
|
|
/* Enabling again should go back to initial state */ |
|
profiler.enable(); |
|
CORRADE_COMPARE(profiler.statistics(), |
|
"Last 0 frames:\n" |
|
" Lag: -.-- s\n" |
|
" Bloat: -.-- B\n" |
|
" Age: -.-- s\n" |
|
" GC: -.-- s\n" |
|
" Optimizations: -.--\n" |
|
" Frame time: -.-- s\n" |
|
" Sanity ratio: -.--\n" |
|
" CPU usage: -.-- %"); |
|
} |
|
|
|
#ifdef MAGNUM_TARGET_GL |
|
void FrameProfilerTest::gl() { |
|
auto&& data = GLData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Test that we use the right state pointers to survive a move */ |
|
Containers::Pointer<FrameProfilerGL> profiler_{InPlaceInit, data.values, 4u}; |
|
FrameProfilerGL profiler = Utility::move(*profiler_); |
|
profiler_ = nullptr; |
|
CORRADE_COMPARE(profiler.values(), data.values); |
|
CORRADE_COMPARE(profiler.maxFrameCount(), 4); |
|
CORRADE_COMPARE(profiler.measurementCount(), data.measurementCount); |
|
|
|
/* MSVC 2015 needs the {} */ |
|
for(auto value: {FrameProfilerGL::Value::CpuDuration, |
|
FrameProfilerGL::Value::FrameTime}) { |
|
if(data.values & value) |
|
CORRADE_VERIFY(!profiler.isMeasurementAvailable(value)); |
|
} |
|
|
|
profiler.beginFrame(); |
|
Utility::System::sleep(1); |
|
profiler.endFrame(); |
|
|
|
profiler.beginFrame(); |
|
profiler.endFrame(); |
|
|
|
Utility::System::sleep(10); |
|
|
|
profiler.beginFrame(); |
|
Utility::System::sleep(1); |
|
profiler.endFrame(); |
|
|
|
profiler.beginFrame(); |
|
Utility::System::sleep(1); |
|
profiler.endFrame(); |
|
|
|
for(std::size_t i = 0; i != data.measurementCount; ++i) |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(i)); |
|
|
|
/* 3/4 frames took 1 ms, the ideal average is 0.75 ms. Can't test upper |
|
bound because (especially on overloaded CIs) it all takes a magnitude |
|
more than expected. Emscripten builds have it as low as 0.5, account for |
|
that. */ |
|
if(data.values & FrameProfilerGL::Value::CpuDuration) { |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(FrameProfilerGL::Value::CpuDuration)); |
|
CORRADE_COMPARE_AS(profiler.cpuDurationMean(), 0.50*1000*1000, |
|
TestSuite::Compare::GreaterOrEqual); |
|
} |
|
|
|
/* 3/4 frames took 1 ms, and one 10 ms, the ideal average is 3.25 ms. Can't |
|
test upper bound because (especially on overloaded CIs) it all takes a |
|
magnitude more than expected. */ |
|
if(data.values & FrameProfilerGL::Value::FrameTime) { |
|
CORRADE_VERIFY(profiler.isMeasurementAvailable(FrameProfilerGL::Value::FrameTime)); |
|
CORRADE_COMPARE_AS(profiler.frameTimeMean(), 3.20*1000*1000, |
|
TestSuite::Compare::GreaterOrEqual); |
|
} |
|
|
|
/* GPU time tested separately */ |
|
} |
|
|
|
void FrameProfilerTest::glNotEnabled() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
FrameProfilerGL profiler{{}, 5}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
profiler.isMeasurementAvailable(FrameProfilerGL::Value::CpuDuration); |
|
profiler.frameTimeMean(); |
|
profiler.cpuDurationMean(); |
|
profiler.gpuDurationMean(); |
|
CORRADE_COMPARE(out.str(), |
|
"DebugTools::FrameProfilerGL::isMeasurementAvailable(): DebugTools::FrameProfilerGL::Value::CpuDuration not enabled\n" |
|
"DebugTools::FrameProfilerGL::frameTimeMean(): not enabled\n" |
|
"DebugTools::FrameProfilerGL::cpuDurationMean(): not enabled\n" |
|
"DebugTools::FrameProfilerGL::gpuDurationMean(): not enabled\n"); |
|
} |
|
#endif |
|
|
|
void FrameProfilerTest::debugUnits() { |
|
std::ostringstream out; |
|
|
|
Debug{&out} << FrameProfiler::Units::Nanoseconds << FrameProfiler::Units(0xf0); |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfiler::Units::Nanoseconds DebugTools::FrameProfiler::Units(0xf0)\n"); |
|
} |
|
|
|
#ifdef MAGNUM_TARGET_GL |
|
void FrameProfilerTest::debugGLValue() { |
|
std::ostringstream out; |
|
|
|
Debug{&out} << FrameProfilerGL::Value::GpuDuration << FrameProfilerGL::Value(0xfff0); |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfilerGL::Value::GpuDuration DebugTools::FrameProfilerGL::Value(0xfff0)\n"); |
|
} |
|
|
|
void FrameProfilerTest::debugGLValues() { |
|
std::ostringstream out; |
|
|
|
Debug{&out} << (FrameProfilerGL::Value::CpuDuration|FrameProfilerGL::Value::FrameTime) << FrameProfilerGL::Values{}; |
|
CORRADE_COMPARE(out.str(), "DebugTools::FrameProfilerGL::Value::FrameTime|DebugTools::FrameProfilerGL::Value::CpuDuration DebugTools::FrameProfilerGL::Values{}\n"); |
|
} |
|
|
|
void FrameProfilerTest::configurationGLValue() { |
|
Utility::ConfigurationGroup c; |
|
|
|
c.setValue("value", FrameProfilerGL::Value::GpuDuration); |
|
CORRADE_COMPARE(c.value("value"), "GpuDuration"); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Value>("value"), FrameProfilerGL::Value::GpuDuration); |
|
|
|
c.setValue("zero", FrameProfilerGL::Value{}); |
|
CORRADE_COMPARE(c.value("zero"), ""); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Value>("zero"), FrameProfilerGL::Value{}); |
|
|
|
c.setValue("invalid", FrameProfilerGL::Value(0xdead)); |
|
CORRADE_COMPARE(c.value("invalid"), ""); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Value>("invalid"), FrameProfilerGL::Value{}); |
|
} |
|
|
|
void FrameProfilerTest::configurationGLValues() { |
|
Utility::ConfigurationGroup c; |
|
|
|
c.setValue("value", FrameProfilerGL::Value::FrameTime|FrameProfilerGL::Value::CpuDuration|FrameProfilerGL::Value::GpuDuration); |
|
CORRADE_COMPARE(c.value("value"), "FrameTime CpuDuration GpuDuration"); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Values>("value"), FrameProfilerGL::Value::FrameTime|FrameProfilerGL::Value::CpuDuration|FrameProfilerGL::Value::GpuDuration); |
|
|
|
c.setValue("empty", FrameProfilerGL::Values{}); |
|
CORRADE_COMPARE(c.value("empty"), ""); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Values>("empty"), FrameProfilerGL::Values{}); |
|
|
|
c.setValue("invalid", FrameProfilerGL::Value::CpuDuration|FrameProfilerGL::Value::GpuDuration|FrameProfilerGL::Value(0xff00)); |
|
CORRADE_COMPARE(c.value("invalid"), "CpuDuration GpuDuration"); |
|
CORRADE_COMPARE(c.value<FrameProfilerGL::Values>("invalid"), FrameProfilerGL::Value::CpuDuration|FrameProfilerGL::Value::GpuDuration); |
|
} |
|
#endif |
|
|
|
}}}} |
|
|
|
CORRADE_TEST_MAIN(Magnum::DebugTools::Test::FrameProfilerTest)
|
|
|