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
breaking changes related to @ref std::string, @ref std::vector and
@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
@relativeref{Corrade,Containers::Pair} with a
@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/StaticArray.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/String.h>
#include "Magnum/Math/Functions.h"
#ifdef MAGNUM_TARGET_GL
@ -45,12 +45,14 @@
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;
_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", );
_begin.delayed = begin;
_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(),
"DebugTools::FrameProfiler::measurementName(): index" << id << "out of range for" << _measurements.size() << "measurements", {});
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;
Debug d{&out, Debug::Flag::NoNewlineAtTheEnd|Debug::Flag::DisableColors};
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,
I'm still suffering this abomination a decade later! */
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) {
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) {
arrayAppend(measurements, InPlaceInit,
"CPU duration", Units::Nanoseconds,
"CPU duration"_s, Units::Nanoseconds,
[](void* state) {
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)
q = GL::TimeQuery{GL::TimeQuery::Target::TimeElapsed};
arrayAppend(measurements, InPlaceInit,
"GPU duration", Units::Nanoseconds,
"GPU duration"_s, Units::Nanoseconds,
UnsignedInt(_state->timeQueries.size()),
[](void* state, UnsignedInt current) {
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)
q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::VertexShaderInvocations};
arrayAppend(measurements, InPlaceInit,
"Vertex fetch ratio", Units::RatioThousandths,
"Vertex fetch ratio"_s, Units::RatioThousandths,
UnsignedInt(_state->verticesSubmittedQueries.size()),
[](void* state, UnsignedInt current) {
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)
q = GL::PipelineStatisticsQuery{GL::PipelineStatisticsQuery::Target::ClippingOutputPrimitives};
arrayAppend(measurements, InPlaceInit,
"Primitives clipped", Units::PercentageThousandths,
"Primitives clipped"_s, Units::PercentageThousandths,
UnsignedInt(_state->clippingInputPrimitivesQueries.size()),
[](void* state, UnsignedInt current) {
static_cast<State*>(state)->clippingInputPrimitivesQueries[current].begin();
@ -674,17 +676,18 @@ Debug& operator<<(Debug& debug, const FrameProfilerGL::Values value) {
namespace Corrade { namespace Utility {
using namespace Containers::Literals;
using namespace Magnum;
#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));
if(1 << bit == UnsignedShort(value))
return DebugTools::FrameProfilerGLValueNames[bit];
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)
if(DebugTools::FrameProfilerGLValueNames[i] == value)
return DebugTools::FrameProfilerGL::Value(1 << i);
@ -692,25 +695,27 @@ DebugTools::FrameProfilerGL::Value ConfigurationValue<DebugTools::FrameProfilerG
return DebugTools::FrameProfilerGL::Value{};
}
std::string ConfigurationValue<DebugTools::FrameProfilerGL::Values>::toString(const DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags) {
std::string out;
Containers::String ConfigurationValue<DebugTools::FrameProfilerGL::Values>::toString(const DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags) {
Containers::String out;
for(std::size_t i = 0; i != Containers::arraySize(DebugTools::FrameProfilerGLValueNames); ++i) {
const auto bit = DebugTools::FrameProfilerGL::Value(1 << i);
if(value & bit) {
if(!out.empty()) out += ' ';
out += DebugTools::FrameProfilerGLValueNames[i];
/** @todo ugh, one allocation per bit, fix when growable String is
a thing ... or maybe some "get set bits" utility and then call
join just once? */
out = " "_s.joinWithoutEmptyParts({out, DebugTools::FrameProfilerGLValueNames[i]});
}
}
return out;
}
DebugTools::FrameProfilerGL::Values ConfigurationValue<DebugTools::FrameProfilerGL::Values>::fromString(const std::string& value, ConfigurationValueFlags) {
const std::vector<std::string> bits = Utility::String::splitWithoutEmptyParts(value);
DebugTools::FrameProfilerGL::Values ConfigurationValue<DebugTools::FrameProfilerGL::Values>::fromString(const Containers::StringView value, ConfigurationValueFlags) {
const Containers::Array<Containers::StringView> bits = value.splitOnWhitespaceWithoutEmptyParts();
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)
if(DebugTools::FrameProfilerGLValueNames[i] == bit)
values |= DebugTools::FrameProfilerGL::Value(1 << i);

45
src/Magnum/DebugTools/FrameProfiler.h

@ -30,13 +30,20 @@
* @m_since{2020,06}
*/
#include <string>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/String.h>
#include "Magnum/Magnum.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 {
/**
@ -289,9 +296,13 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler {
*
* The @p id corresponds to the index of the measurement in the list
* 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
@ -359,7 +370,7 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler {
* is not available yet, prints placeholder values for these.
* @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
@ -427,8 +438,12 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler::Measurement {
* the measured value
* @param state State pointer passed to both @p begin and @p end
* 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
@ -458,13 +473,17 @@ class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler::Measurement {
* corresponds to current frame.
* @param state State pointer passed to both @p begin and @p end
* 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:
friend FrameProfiler;
std::string _name;
Containers::String _name;
union {
void(*immediate)(void*);
void(*delayed)(void*, UnsignedInt);
@ -733,16 +752,18 @@ template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools
/**
* @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
*
* 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
* 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
@ -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
* 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

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

@ -124,6 +124,7 @@ void FrameProfilerGLTest::test() {
CORRADE_COMPARE(profiler.maxFrameCount(), 4);
/* MSVC 2015 needs the {} */
UnsignedInt i = 0;
for(auto value: {FrameProfilerGL::Value::CpuDuration,
FrameProfilerGL::Value::GpuDuration,
#ifndef MAGNUM_TARGET_GLES
@ -131,8 +132,11 @@ void FrameProfilerGLTest::test() {
FrameProfilerGL::Value::PrimitiveClipRatio
#endif
}) {
if(data.values & value)
CORRADE_VERIFY(!profiler.isMeasurementAvailable(value));
if(!(data.values & value)) continue;
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();

Loading…
Cancel
Save