class new in 2020.06
#include <Magnum/DebugTools/FrameProfiler.h>
FrameProfiler Frame profiler.
A generic implementation of a frame profiler supporting a moving average over a set of frames as well as delayed measurements to avoid stalls when querying the results. This class alone doesn't provide any pre-defined measurements, see for example FrameProfilerGL that provides common measurements like CPU and GPU time.
Basic usage
Measurements are performed by calling beginFrame() and endFrame() at designated points in the frame:
void MyApp::drawEvent() { _profiler.beginFrame(); // actual drawing code … _profiler.endFrame(); // possibly other code (such as UI) you don't want to have included in the // measurements … swapBuffers(); redraw(); }
In order to have stable profiling results, the application needs to redraw constantly. However for applications that otherwise redraw only on change it might be wasteful — to account for this, it's possible to toggle the profiler operation using enable() / disable() and then redraw() can be called only if isEnabled() returns true
.
Data for all measurements is then available through measurementName(), measurementUnits() and measurementMean(). For a convenient overview of all measured values you can call statistics() and feed its output to a UI library or something that can render text. Alternatively, if you don't want to bother with text rendering, call printStatistics() to have the output periodically printed to the console. If an interactive terminal is detected, the output will be colored and refreshing itself in place. Together with the on-demand profiling, it could look like this, refreshing the output every 10 frames:
_profiler.endFrame(); _profiler.printStatistics(10); swapBuffers(); if(_profiler.isEnabled()) redraw(); }
And here's a sample output on the terminal — using a fully configured FrameProfilerGL:
Last 50 frames: Frame time: 16.65 ms CPU duration: 14.72 ms GPU duration: 10.89 ms Vertex fetch ratio: 0.24 Primitives clipped: 59.67 %
Setting up measurements
Unless you're using this class through FrameProfilerGL, measurements have to be set up by passing Measurement instances to the setup() function or to the constructor, together with specifying count of frames for the moving average. A CPU duration measurements using the std::
using std::chrono::high_resolution_clock; high_resolution_clock::time_point frameBeginTime; DebugTools::FrameProfiler profiler{{ DebugTools::FrameProfiler::Measurement{"CPU time", DebugTools::FrameProfiler::Units::Nanoseconds, [](void* state) { *static_cast<high_resolution_clock::time_point*>(state) = high_resolution_clock::now(); }, [](void* state) { return UnsignedLong( std::chrono::duration_cast<std::chrono::nanoseconds>( *static_cast<high_resolution_clock::time_point*>(state) - high_resolution_clock::now()).count()); }, &frameBeginTime} }, 50};
In the above case, the measurement result is available immediately on frame end. That's not always the case, and for example GPU queries need a few frames delay to avoid stalls from CPU/GPU synchronization. The following snippet sets up sample count measurement with a delay, using three separate GL::current
/ previous
parameters passed to each callback:
GL::SampleQuery queries[3]{ GL::SampleQuery{GL::SampleQuery::Target::SamplesPassed}, GL::SampleQuery{GL::SampleQuery::Target::SamplesPassed}, GL::SampleQuery{GL::SampleQuery::Target::SamplesPassed} }; DebugTools::FrameProfiler _profiler{{ DebugTools::FrameProfiler::Measurement{"Samples", DebugTools::FrameProfiler::Units::Count, UnsignedInt(Containers::arraySize(queries)), [](void* state, UnsignedInt current) { static_cast<GL::SampleQuery*>(state)[current].begin(); }, [](void* state, UnsignedInt current) { static_cast<GL::SampleQuery*>(state)[current].end(); }, [](void* state, UnsignedInt previous, UnsignedInt) { return static_cast<GL::SampleQuery*>(state)[previous] .result<UnsignedLong>(); }, queries} }, 50};
Derived classes
- class FrameProfilerGL new in 2020.06
- OpenGL frame profiler.
Public types
- class Measurement
- Measurement.
- enum class Units: UnsignedByte { Nanoseconds, Bytes, Count, RatioThousandths, PercentageThousandths }
- Measurement units.
Constructors, destructors, conversion operators
- FrameProfiler() explicit noexcept
- Default constructor.
-
FrameProfiler(Containers::
Array<Measurement>&& measurements, UnsignedInt maxFrameCount) explicit noexcept - Constructor.
-
FrameProfiler(std::
initializer_list<Measurement> measurements, UnsignedInt maxFrameCount) explicit - FrameProfiler(const FrameProfiler&) deleted
- Copying is not allowed.
- FrameProfiler(FrameProfiler&&) noexcept
- Move constructor.
Public functions
- auto operator=(const FrameProfiler&) -> FrameProfiler& deleted
- Copying is not allowed.
- auto operator=(FrameProfiler&&) -> FrameProfiler& noexcept
- Move assignment.
-
void setup(Containers::
Array<Measurement>&& measurements, UnsignedInt maxFrameCount) - Setup measurements.
-
void setup(std::
initializer_list<Measurement> measurements, UnsignedInt maxFrameCount) - auto isEnabled() const -> bool
- Whether the profiling is enabled.
- void enable()
- Enable the profiler.
- void disable()
- Disable the profiler.
- void beginFrame()
- Begin a frame.
- void endFrame()
- End a frame.
- auto maxFrameCount() const -> UnsignedInt
- Max count of measured frames.
- auto measuredFrameCount() const -> UnsignedInt
- Count of measured frames.
- auto measurementCount() const -> UnsignedInt
- Measurement count.
-
auto measurementName(UnsignedInt id) const -> Containers::
StringView - Measurement name.
- auto measurementUnits(UnsignedInt id) const -> Units
- Measurement units.
- auto measurementDelay(UnsignedInt id) const -> UnsignedInt
- Measurement delay.
- auto isMeasurementAvailable(UnsignedInt id) const -> bool
- Whether given measurement is available.
- auto measurementData(UnsignedInt id, UnsignedInt frame) const -> UnsignedLong
- Measurement data at given frame.
- auto measurementMean(UnsignedInt id) const -> Double
- Measurement mean.
-
auto statistics() const -> Containers::
String - Overview of all measurements.
- void printStatistics(UnsignedInt frequency) const
- Print an overview of all measurements to a console at given rate.
- void printStatistics(Debug& out, UnsignedInt frequency) const
- Print an overview of all measurements to given output at given rate.
- void printStatistics(Debug&& out, UnsignedInt frequency) const
Enum documentation
enum class Magnum:: DebugTools:: FrameProfiler:: Units: UnsignedByte
Measurement units.
Enumerators | |
---|---|
Nanoseconds |
Nanoseconds, measuring for example elapsed time. Depending on the magnitude, statistics() can show them as microseconds, milliseconds or seconds. |
Bytes |
Bytes, measuring for example memory usage, bandwidth. Depending on the magnitude, statistics() can show them as kB, MB, GB (with a multiplier of 1024). |
Count |
Generic count. For discrete values that don't fit any of the above. Depending on the magnitude, statistics() can show the value as k, M or G (with a multiplier of 1000). |
RatioThousandths |
Ratio expressed in 1/1000s. statistics() divides the value by 1000 and depending on the magnitude it can show it also as k, M or G (with a multiplier of 1000). |
PercentageThousandths |
Percentage expressed in 1/1000s. statistics() divides the value by 1000 and appends a % sign. |
Function documentation
Magnum:: DebugTools:: FrameProfiler:: FrameProfiler() explicit noexcept
Default constructor.
Call setup() to populate the profiler with measurements.
Magnum:: DebugTools:: FrameProfiler:: FrameProfiler(Containers:: Array<Measurement>&& measurements,
UnsignedInt maxFrameCount) explicit noexcept
Constructor.
Equivalent to default-constructing an instance and calling setup() afterwards.
Magnum:: DebugTools:: FrameProfiler:: FrameProfiler(std:: initializer_list<Measurement> measurements,
UnsignedInt maxFrameCount) explicit
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
void Magnum:: DebugTools:: FrameProfiler:: setup(Containers:: Array<Measurement>&& measurements,
UnsignedInt maxFrameCount)
Setup measurements.
Parameters | |
---|---|
measurements | List of measurements |
maxFrameCount | Max frame count over which to calculate a moving average. Expected to be at least 1 . |
Calling setup() on an already set up profiler will replace existing measurements with measurements
and reset measuredFrameCount() back to 0
.
void Magnum:: DebugTools:: FrameProfiler:: setup(std:: initializer_list<Measurement> measurements,
UnsignedInt maxFrameCount)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
void Magnum:: DebugTools:: FrameProfiler:: enable()
Enable the profiler.
The profiler is enabled implicitly after construction. When this function is called, it discards all measured data, effectively making measuredFrameCount() zero. If you want to reset the profiler to measure different values as well, call setup().
void Magnum:: DebugTools:: FrameProfiler:: disable()
Disable the profiler.
Disabling the profiler will make beginFrame() and endFrame() a no-op, effectively freezing all reported measurements until the profiler is enabled again.
void Magnum:: DebugTools:: FrameProfiler:: beginFrame()
Begin a frame.
Has to be called at the beginning of a frame and be paired with a corresponding endFrame(). Calls begin
functions in all Measurement instances passed to setup(). If the profiler is disabled, the function is a no-op.
void Magnum:: DebugTools:: FrameProfiler:: endFrame()
End a frame.
Has to be called at the end of frame, before buffer swap, and be paired with a corresponding beginFrame(). Calls end
functions in all Measurement instances passed to setup() and query
functions on all measurements that are sufficiently delayed, saving their output. If the profiler is disabled, the function is a no-op.
UnsignedInt Magnum:: DebugTools:: FrameProfiler:: maxFrameCount() const
Max count of measured frames.
How many frames to calculate a moving average from. At the beginning of a measurement when there's not enough frames, the average is calculated only from measuredFrameCount(). Always at least 1
.
UnsignedInt Magnum:: DebugTools:: FrameProfiler:: measuredFrameCount() const
Count of measured frames.
Count of times endFrame() was called, but at most maxFrameCount(), after which the profiler calculates a moving average over last maxFrameCount() frames only. Actual data availability depends on measurementDelay().
UnsignedInt Magnum:: DebugTools:: FrameProfiler:: measurementCount() const
Measurement count.
Count of Measurement instances passed to setup(). If setup() was not called yet, returns 0
.
Containers:: StringView Magnum:: DebugTools:: FrameProfiler:: measurementName(UnsignedInt id) const
Measurement name.
The id
corresponds to the index of the measurement in the list passed to setup(). Expects that id
is less than measurementCount(). The returned view is always Containers::
Units Magnum:: DebugTools:: FrameProfiler:: measurementUnits(UnsignedInt id) const
Measurement units.
The id
corresponds to the index of the measurement in the list passed to setup(). Expects that id
is less than measurementCount().
UnsignedInt Magnum:: DebugTools:: FrameProfiler:: measurementDelay(UnsignedInt id) const
Measurement delay.
How many beginFrame() / endFrame() call pairs needs to be performed before a value for given measurement is available. Always at least 1
. The id
corresponds to the index of the measurement in the list passed to setup(). Expects that id
is less than measurementCount().
bool Magnum:: DebugTools:: FrameProfiler:: isMeasurementAvailable(UnsignedInt id) const
Whether given measurement is available.
Returns true
if measuredFrameCount() is at least measurementDelay() for given id
, false
otherwise. The id
corresponds to the index of the measurement in the list passed to setup(). Expects that id
is less than measurementCount().
UnsignedLong Magnum:: DebugTools:: FrameProfiler:: measurementData(UnsignedInt id,
UnsignedInt frame) const
Measurement data at given frame.
A frame
value of 0
is the oldest recorded frame and can go up to measurementCount() lessened by measurementDelay() or maxFrameCount() minus one, whichever is smaller. Expects that id
is less than measurementCount() and at least one measurement is available.
Double Magnum:: DebugTools:: FrameProfiler:: measurementMean(UnsignedInt id) const
Measurement mean.
Returns a moving average of previous measurements out of the total values:
The id
corresponds to the index of the measurement in the list passed to setup(). Expects that id
is less than measurementCount() and that the measurement is available.
Containers:: String Magnum:: DebugTools:: FrameProfiler:: statistics() const
Overview of all measurements.
Returns a formatted string with names, means and units of all measurements in the order they were added. If some measurement data is not available yet, prints placeholder values for these.
void Magnum:: DebugTools:: FrameProfiler:: printStatistics(UnsignedInt frequency) const
Print an overview of all measurements to a console at given rate.
Expected to be called every frame. If profiling is enabled, on every frequency
th frame prints the same information as statistics(), but in addition, if the output is a TTY, it's colored and overwrites itself instead of filling up the terminal history. If profiling is disabled, does nothing.
void Magnum:: DebugTools:: FrameProfiler:: printStatistics(Debug& out,
UnsignedInt frequency) const
Print an overview of all measurements to given output at given rate.
Compared to printStatistics(UnsignedInt) const prints to given out
(which can be also Corrade::
void Magnum:: DebugTools:: FrameProfiler:: printStatistics(Debug&& out,
UnsignedInt frequency) const
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
Debug& operator<<(Debug& debug,
FrameProfiler:: Units value) new in 2020.06
Debug output operator.