Browse Source

DebugTools: port FrameProfiler away from std::string.

One of the last remaining leftovers.
pull/499/head
Vladimír Vondruš 3 years ago
parent
commit
cec3c21c30
  1. 4
      doc/changelog.dox
  2. 45
      src/Magnum/DebugTools/FrameProfiler.cpp
  3. 45
      src/Magnum/DebugTools/FrameProfiler.h
  4. 8
      src/Magnum/DebugTools/Test/FrameProfilerGLTest.cpp

4
doc/changelog.dox

@ -1137,6 +1137,10 @@ See also:
- As part of the ongoing STL header dependency cleanup, the following - As part of the ongoing STL header dependency cleanup, the following
breaking changes related to @ref std::string, @ref std::vector and breaking changes related to @ref std::string, @ref std::vector and
@ref std::pair are done: @ref std::pair are done:
- @ref DebugTools::FrameProfiler::measurementName() and
@ref DebugTools::FrameProfiler::statistics() now return a
@relativeref{Corrade,Containers::StringView} /
@relativeref{Corrade,Containers::String} instead of a @ref std::string
- @ref GL::AbstractShaderProgram::validate() now returns a - @ref GL::AbstractShaderProgram::validate() now returns a
@relativeref{Corrade,Containers::Pair} with a @relativeref{Corrade,Containers::Pair} with a
@relativeref{Corrade,Containers::String} instead of a @ref std::pair @relativeref{Corrade,Containers::String} instead of a @ref std::pair

45
src/Magnum/DebugTools/FrameProfiler.cpp

@ -31,9 +31,9 @@
#include <Corrade/Containers/GrowableArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/String.h> #include <Corrade/Containers/String.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Containers/StringIterable.h>
#include <Corrade/Containers/StringStl.h> /** @todo drop once Debug is stream-free */
#include <Corrade/Utility/Format.h> #include <Corrade/Utility/Format.h>
#include <Corrade/Utility/String.h>
#include "Magnum/Math/Functions.h" #include "Magnum/Math/Functions.h"
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
@ -45,12 +45,14 @@
namespace Magnum { namespace DebugTools { namespace Magnum { namespace DebugTools {
FrameProfiler::Measurement::Measurement(const std::string& name, const Units units, void(*const begin)(void*), UnsignedLong(*const end)(void*), void* const state): _name{name}, _end{nullptr}, _state{state}, _units{units}, _delay{0} { using namespace Containers::Literals;
FrameProfiler::Measurement::Measurement(const Containers::StringView name, const Units units, void(*const begin)(void*), UnsignedLong(*const end)(void*), void* const state): _name{Containers::String::nullTerminatedGlobalView(name)}, _end{nullptr}, _state{state}, _units{units}, _delay{0} {
_begin.immediate = begin; _begin.immediate = begin;
_query.immediate = end; _query.immediate = end;
} }
FrameProfiler::Measurement::Measurement(const std::string& name, const Units units, const UnsignedInt delay, void(*const begin)(void*, UnsignedInt), void(*const end)(void*, UnsignedInt), UnsignedLong(*const query)(void*, UnsignedInt, UnsignedInt), void* const state): _name{name}, _state{state}, _units{units}, _delay{delay} { FrameProfiler::Measurement::Measurement(const Containers::StringView name, const Units units, const UnsignedInt delay, void(*const begin)(void*, UnsignedInt), void(*const end)(void*, UnsignedInt), UnsignedLong(*const query)(void*, UnsignedInt, UnsignedInt), void* const state): _name{Containers::String::nullTerminatedGlobalView(name)}, _state{state}, _units{units}, _delay{delay} {
CORRADE_ASSERT(delay >= 1, "DebugTools::FrameProfiler::Measurement: delay can't be zero", ); CORRADE_ASSERT(delay >= 1, "DebugTools::FrameProfiler::Measurement: delay can't be zero", );
_begin.delayed = begin; _begin.delayed = begin;
_end = end; _end = end;
@ -234,7 +236,7 @@ void FrameProfiler::endFrame() {
} }
} }
std::string FrameProfiler::measurementName(const UnsignedInt id) const { Containers::StringView FrameProfiler::measurementName(const UnsignedInt id) const {
CORRADE_ASSERT(id < _measurements.size(), CORRADE_ASSERT(id < _measurements.size(),
"DebugTools::FrameProfiler::measurementName(): index" << id << "out of range for" << _measurements.size() << "measurements", {}); "DebugTools::FrameProfiler::measurementName(): index" << id << "out of range for" << _measurements.size() << "measurements", {});
return _measurements[id]._name; return _measurements[id]._name;
@ -379,7 +381,7 @@ void FrameProfiler::printStatisticsInternal(Debug& out) const {
} }
} }
std::string FrameProfiler::statistics() const { Containers::String FrameProfiler::statistics() const {
std::ostringstream out; std::ostringstream out;
Debug d{&out, Debug::Flag::NoNewlineAtTheEnd|Debug::Flag::DisableColors}; Debug d{&out, Debug::Flag::NoNewlineAtTheEnd|Debug::Flag::DisableColors};
printStatisticsInternal(d); printStatisticsInternal(d);
@ -471,7 +473,7 @@ void FrameProfilerGL::setup(const Values values, const UnsignedInt maxFrameCount
should have flipped the table and learn carpentry instead. BUT NO, should have flipped the table and learn carpentry instead. BUT NO,
I'm still suffering this abomination a decade later! */ I'm still suffering this abomination a decade later! */
arrayAppend(measurements, InPlaceInit, arrayAppend(measurements, InPlaceInit,
"Frame time", Units::Nanoseconds, UnsignedInt(Containers::arraySize(_state->frameTimeStartFrame)), "Frame time"_s, Units::Nanoseconds, UnsignedInt(Containers::arraySize(_state->frameTimeStartFrame)),
[](void* state, UnsignedInt current) { [](void* state, UnsignedInt current) {
static_cast<State*>(state)->frameTimeStartFrame[current] = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); static_cast<State*>(state)->frameTimeStartFrame[current] = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}, },
@ -485,7 +487,7 @@ void FrameProfilerGL::setup(const Values values, const UnsignedInt maxFrameCount
} }
if(values & Value::CpuDuration) { if(values & Value::CpuDuration) {
arrayAppend(measurements, InPlaceInit, arrayAppend(measurements, InPlaceInit,
"CPU duration", Units::Nanoseconds, "CPU duration"_s, Units::Nanoseconds,
[](void* state) { [](void* state) {
static_cast<State*>(state)->cpuDurationStartFrame = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); static_cast<State*>(state)->cpuDurationStartFrame = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}, },
@ -499,7 +501,7 @@ void FrameProfilerGL::setup(const Values values, const UnsignedInt maxFrameCount
for(GL::TimeQuery& q: _state->timeQueries) for(GL::TimeQuery& q: _state->timeQueries)
q = GL::TimeQuery{GL::TimeQuery::Target::TimeElapsed}; q = GL::TimeQuery{GL::TimeQuery::Target::TimeElapsed};
arrayAppend(measurements, InPlaceInit, arrayAppend(measurements, InPlaceInit,
"GPU duration", Units::Nanoseconds, "GPU duration"_s, Units::Nanoseconds,
UnsignedInt(_state->timeQueries.size()), UnsignedInt(_state->timeQueries.size()),
[](void* state, UnsignedInt current) { [](void* state, UnsignedInt current) {
static_cast<State*>(state)->timeQueries[current].begin(); static_cast<State*>(state)->timeQueries[current].begin();
@ -519,7 +521,7 @@ void FrameProfilerGL::setup(const Values values, const UnsignedInt maxFrameCount
for(GL::PipelineStatisticsQuery& q: _state->vertexShaderInvocationsQueries) for(GL::PipelineStatisticsQuery& q: _state->vertexShaderInvocationsQueries)
q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::VertexShaderInvocations}; q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::VertexShaderInvocations};
arrayAppend(measurements, InPlaceInit, arrayAppend(measurements, InPlaceInit,
"Vertex fetch ratio", Units::RatioThousandths, "Vertex fetch ratio"_s, Units::RatioThousandths,
UnsignedInt(_state->verticesSubmittedQueries.size()), UnsignedInt(_state->verticesSubmittedQueries.size()),
[](void* state, UnsignedInt current) { [](void* state, UnsignedInt current) {
static_cast<State*>(state)->verticesSubmittedQueries[current].begin(); static_cast<State*>(state)->verticesSubmittedQueries[current].begin();
@ -544,7 +546,7 @@ void FrameProfilerGL::setup(const Values values, const UnsignedInt maxFrameCount
for(GL::PipelineStatisticsQuery& q: _state->clippingOutputPrimitivesQueries) for(GL::PipelineStatisticsQuery& q: _state->clippingOutputPrimitivesQueries)
q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::ClippingOutputPrimitives}; q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::ClippingOutputPrimitives};
arrayAppend(measurements, InPlaceInit, arrayAppend(measurements, InPlaceInit,
"Primitives clipped", Units::PercentageThousandths, "Primitives clipped"_s, Units::PercentageThousandths,
UnsignedInt(_state->clippingInputPrimitivesQueries.size()), UnsignedInt(_state->clippingInputPrimitivesQueries.size()),
[](void* state, UnsignedInt current) { [](void* state, UnsignedInt current) {
static_cast<State*>(state)->clippingInputPrimitivesQueries[current].begin(); static_cast<State*>(state)->clippingInputPrimitivesQueries[current].begin();
@ -674,17 +676,18 @@ Debug& operator<<(Debug& debug, const FrameProfilerGL::Values value) {
namespace Corrade { namespace Utility { namespace Corrade { namespace Utility {
using namespace Containers::Literals;
using namespace Magnum; using namespace Magnum;
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
std::string ConfigurationValue<DebugTools::FrameProfilerGL::Value>::toString(const DebugTools::FrameProfilerGL::Value value, ConfigurationValueFlags) { Containers::StringView ConfigurationValue<DebugTools::FrameProfilerGL::Value>::toString(const DebugTools::FrameProfilerGL::Value value, ConfigurationValueFlags) {
const UnsignedInt bit = Math::log2(UnsignedShort(value)); const UnsignedInt bit = Math::log2(UnsignedShort(value));
if(1 << bit == UnsignedShort(value)) if(1 << bit == UnsignedShort(value))
return DebugTools::FrameProfilerGLValueNames[bit]; return DebugTools::FrameProfilerGLValueNames[bit];
return ""; return "";
} }
DebugTools::FrameProfilerGL::Value ConfigurationValue<DebugTools::FrameProfilerGL::Value>::fromString(const std::string& value, ConfigurationValueFlags) { DebugTools::FrameProfilerGL::Value ConfigurationValue<DebugTools::FrameProfilerGL::Value>::fromString(const Containers::StringView value, ConfigurationValueFlags) {
for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i) for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i)
if(DebugTools::FrameProfilerGLValueNames[i] == value) if(DebugTools::FrameProfilerGLValueNames[i] == value)
return DebugTools::FrameProfilerGL::Value(1 << i); return DebugTools::FrameProfilerGL::Value(1 << i);
@ -692,25 +695,27 @@ DebugTools::FrameProfilerGL::Value ConfigurationValue<DebugTools::FrameProfilerG
return DebugTools::FrameProfilerGL::Value{}; return DebugTools::FrameProfilerGL::Value{};
} }
std::string ConfigurationValue<DebugTools::FrameProfilerGL::Values>::toString(const DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags) { Containers::String ConfigurationValue<DebugTools::FrameProfilerGL::Values>::toString(const DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags) {
std::string out; Containers::String out;
for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i) { for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i) {
const auto bit = DebugTools::FrameProfilerGL::Value(1 << i); const auto bit = DebugTools::FrameProfilerGL::Value(1 << i);
if(value & bit) { if(value & bit) {
if(!out.empty()) out += ' '; /** @todo ugh, one allocation per bit, fix when growable String is
out += DebugTools::FrameProfilerGLValueNames[i]; a thing ... or maybe some "get set bits" utility and then call
join just once? */
out = " "_s.joinWithoutEmptyParts({out, DebugTools::FrameProfilerGLValueNames[i]});
} }
} }
return out; return out;
} }
DebugTools::FrameProfilerGL::Values ConfigurationValue<DebugTools::FrameProfilerGL::Values>::fromString(const std::string& value, ConfigurationValueFlags) { DebugTools::FrameProfilerGL::Values ConfigurationValue<DebugTools::FrameProfilerGL::Values>::fromString(const Containers::StringView value, ConfigurationValueFlags) {
const std::vector<std::string> bits = Utility::String::splitWithoutEmptyParts(value); const Containers::Array<Containers::StringView> bits = value.splitOnWhitespaceWithoutEmptyParts();
DebugTools::FrameProfilerGL::Values values; DebugTools::FrameProfilerGL::Values values;
for(const std::string& bit: bits) for(const Containers::StringView bit: bits)
for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i) for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i)
if(DebugTools::FrameProfilerGLValueNames[i] == bit) if(DebugTools::FrameProfilerGLValueNames[i] == bit)
values |= DebugTools::FrameProfilerGL::Value(1 << i); values |= DebugTools::FrameProfilerGL::Value(1 << i);

45
src/Magnum/DebugTools/FrameProfiler.h

@ -30,13 +30,20 @@
* @m_since{2020,06} * @m_since{2020,06}
*/ */
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/String.h>
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
#include "Magnum/DebugTools/visibility.h" #include "Magnum/DebugTools/visibility.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Measurement used to take a std::string, measurementName() and statistics()
used to be a std::string. Not ideal for the return types, but at least
something. */
#include <Corrade/Containers/StringStl.h>
#endif
namespace Magnum { namespace DebugTools { namespace Magnum { namespace DebugTools {
/** /**
@ -289,9 +296,13 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler {
* *
* The @p id corresponds to the index of the measurement in the list * The @p id corresponds to the index of the measurement in the list
* passed to @ref setup(). Expects that @p id is less than * passed to @ref setup(). Expects that @p id is less than
* @ref measurementCount(). * @ref measurementCount(). The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated};
* @relativeref{Corrade,Containers::StringViewFlag::Global} is set if
* the corresponding @ref Measurement was created with a global
* null-terminated string view.
*/ */
std::string measurementName(UnsignedInt id) const; Containers::StringView measurementName(UnsignedInt id) const;
/** /**
* @brief Measurement units * @brief Measurement units
@ -359,7 +370,7 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler {
* is not available yet, prints placeholder values for these. * is not available yet, prints placeholder values for these.
* @see @ref isMeasurementAvailable(), @ref isEnabled() * @see @ref isMeasurementAvailable(), @ref isEnabled()
*/ */
std::string statistics() const; Containers::String statistics() const;
/** /**
* @brief Print an overview of all measurements to a console at given rate * @brief Print an overview of all measurements to a console at given rate
@ -427,8 +438,12 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler::Measurement {
* the measured value * the measured value
* @param state State pointer passed to both @p begin and @p end * @param state State pointer passed to both @p begin and @p end
* as a first argument * as a first argument
*
* If @p name is @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade::Containers::StringViewFlag,Global}, no
* internal copy of the string is made.
*/ */
explicit Measurement(const std::string& name, Units units, void(*begin)(void*), UnsignedLong(*end)(void*), void* state); explicit Measurement(Containers::StringView name, Units units, void(*begin)(void*), UnsignedLong(*end)(void*), void* state);
/** /**
* @brief Construct a delayed measurement * @brief Construct a delayed measurement
@ -458,13 +473,17 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler::Measurement {
* corresponds to current frame. * corresponds to current frame.
* @param state State pointer passed to both @p begin and @p end * @param state State pointer passed to both @p begin and @p end
* as a first argument * as a first argument
*
* If @p name is @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade::Containers::StringViewFlag,Global}, no
* internal copy of the string is made.
*/ */
explicit Measurement(const std::string& name, Units units, UnsignedInt delay, void(*begin)(void*, UnsignedInt), void(*end)(void*, UnsignedInt), UnsignedLong(*query)(void*, UnsignedInt, UnsignedInt), void* state); explicit Measurement(Containers::StringView name, Units units, UnsignedInt delay, void(*begin)(void*, UnsignedInt), void(*end)(void*, UnsignedInt), UnsignedLong(*query)(void*, UnsignedInt, UnsignedInt), void* state);
private: private:
friend FrameProfiler; friend FrameProfiler;
std::string _name; Containers::String _name;
union { union {
void(*immediate)(void*); void(*immediate)(void*);
void(*delayed)(void*, UnsignedInt); void(*delayed)(void*, UnsignedInt);
@ -733,16 +752,18 @@ template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools
/** /**
* @brief Writes enum value as a string * @brief Writes enum value as a string
* *
* If the value is invalid, returns an empty string. * If the value is invalid, returns an empty string. The returned view is
* always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade,Containers::StringViewFlag::Global}.
*/ */
static std::string toString(Magnum::DebugTools::FrameProfilerGL::Value value, ConfigurationValueFlags); static Containers::StringView toString(Magnum::DebugTools::FrameProfilerGL::Value value, ConfigurationValueFlags);
/** /**
* @brief Reads enum value as a string * @brief Reads enum value as a string
* *
* If the string is invalid, returns a zero (invalid) value. * If the string is invalid, returns a zero (invalid) value.
*/ */
static Magnum::DebugTools::FrameProfilerGL::Value fromString(const std::string& stringValue, ConfigurationValueFlags); static Magnum::DebugTools::FrameProfilerGL::Value fromString(Containers::StringView stringValue, ConfigurationValueFlags);
}; };
/** /**
@ -758,7 +779,7 @@ template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools
* Writes the enum set as a sequence of flag names separated by spaces. If * Writes the enum set as a sequence of flag names separated by spaces. If
* the value is invalid, returns an empty string. * the value is invalid, returns an empty string.
*/ */
static std::string toString(Magnum::DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags); static Containers::String toString(Magnum::DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags);
/** /**
* @brief Reads enum set value as a string * @brief Reads enum set value as a string
@ -766,7 +787,7 @@ template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools
* Assumes the string is a sequence of flag names separated by spaces. If * Assumes the string is a sequence of flag names separated by spaces. If
* the value is invalid, returns an empty set. * the value is invalid, returns an empty set.
*/ */
static Magnum::DebugTools::FrameProfilerGL::Values fromString(const std::string& stringValue, ConfigurationValueFlags); static Magnum::DebugTools::FrameProfilerGL::Values fromString(Containers::StringView stringValue, ConfigurationValueFlags);
}; };
#endif #endif

8
src/Magnum/DebugTools/Test/FrameProfilerGLTest.cpp

@ -124,6 +124,7 @@ void FrameProfilerGLTest::test() {
CORRADE_COMPARE(profiler.maxFrameCount(), 4); CORRADE_COMPARE(profiler.maxFrameCount(), 4);
/* MSVC 2015 needs the {} */ /* MSVC 2015 needs the {} */
UnsignedInt i = 0;
for(auto value: {FrameProfilerGL::Value::CpuDuration, for(auto value: {FrameProfilerGL::Value::CpuDuration,
FrameProfilerGL::Value::GpuDuration, FrameProfilerGL::Value::GpuDuration,
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -131,8 +132,11 @@ void FrameProfilerGLTest::test() {
FrameProfilerGL::Value::PrimitiveClipRatio FrameProfilerGL::Value::PrimitiveClipRatio
#endif #endif
}) { }) {
if(data.values & value) if(!(data.values & value)) continue;
CORRADE_VERIFY(!profiler.isMeasurementAvailable(value));
CORRADE_VERIFY(!profiler.isMeasurementAvailable(value));
/* The names should not be allocated */
CORRADE_COMPARE(profiler.measurementName(i++).flags(), Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global);
} }
profiler.beginFrame(); profiler.beginFrame();

Loading…
Cancel
Save