Browse Source

Initial version of Profiler class.

vectorfields
Vladimír Vondruš 14 years ago
parent
commit
37b6049a62
  1. 2
      src/CMakeLists.txt
  2. 111
      src/Profiler.cpp
  3. 206
      src/Profiler.h

2
src/CMakeLists.txt

@ -22,6 +22,7 @@ set(Magnum_SRCS
Framebuffer.cpp
IndexedMesh.cpp
Mesh.cpp
Profiler.cpp
Query.cpp
Renderbuffer.cpp
Shader.cpp
@ -46,6 +47,7 @@ set(Magnum_HEADERS
IndexedMesh.h
Magnum.h
Mesh.h
Profiler.h
Query.h
Renderbuffer.h
Shader.h

111
src/Profiler.cpp

@ -0,0 +1,111 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Profiler.h"
#include <algorithm>
#include <numeric>
#include <Utility/Debug.h>
using namespace std;
namespace Magnum {
Profiler::Section Profiler::addSection(const string& name) {
CORRADE_ASSERT(!enabled, "Profiler: cannot add section when profiling is enabled", 0);
sections.push_back(name);
return sections.size()-1;
}
void Profiler::setMeasureDuration(size_t frames) {
CORRADE_ASSERT(!enabled, "Profiler: cannot set measure duration when profiling is enabled", );
measureDuration = frames;
}
void Profiler::enable() {
enabled = true;
frameData.assign(measureDuration*sections.size(), chrono::high_resolution_clock::duration::zero());
totalData.assign(sections.size(), chrono::high_resolution_clock::duration::zero());
frameCount = 0;
}
void Profiler::disable() {
enabled = false;
}
void Profiler::start(Section section) {
if(!enabled) return;
CORRADE_ASSERT(section < sections.size(), "Profiler: unknown section passed to start()", );
save();
currentSection = section;
}
void Profiler::stop() {
if(!enabled) return;
save();
previousTime = chrono::high_resolution_clock::time_point();
}
void Profiler::save() {
auto now = chrono::high_resolution_clock::now();
/* If the profiler is already running, add time to given section */
if(previousTime != chrono::high_resolution_clock::time_point())
frameData[currentFrame*sections.size()+currentSection] += now-previousTime;
/* Set current time as previous for next section */
previousTime = now;
}
void Profiler::nextFrame() {
if(!enabled) return;
/* Next frame index */
size_t nextFrame = (currentFrame+1) % measureDuration;
/* Add times of current frame to total */
for(size_t i = 0; i != sections.size(); ++i)
totalData[i] += frameData[currentFrame*sections.size()+i];
/* Subtract times of next frame from total and erase them */
for(size_t i = 0; i != sections.size(); ++i) {
totalData[i] -= frameData[nextFrame*sections.size()+i];
frameData[nextFrame*sections.size()+i] = chrono::high_resolution_clock::duration::zero();
}
/* Advance to next frame */
currentFrame = nextFrame;
if(frameCount < measureDuration) ++frameCount;
}
void Profiler::printStatistics() {
if(!enabled) return;
vector<size_t> totalSorted(sections.size());
iota(totalSorted.begin(), totalSorted.end(), 0);
sort(totalSorted.begin(), totalSorted.end(), [this](size_t i, size_t j){return totalData[i] > totalData[j];});
Corrade::Utility::Debug() << "Statistics for last" << measureDuration << "frames:";
for(size_t i = 0; i != sections.size(); ++i)
Corrade::Utility::Debug() << ' ' << sections[totalSorted[i]] << chrono::microseconds(totalData[totalSorted[i]]).count()/frameCount << u8"µs";
}
}

206
src/Profiler.h

@ -0,0 +1,206 @@
#ifndef Magnum_Profiler_h
#define Magnum_Profiler_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Profiler
*/
#include <chrono>
#include <initializer_list>
#include <string>
#include <vector>
#include "magnumVisibility.h"
namespace Magnum {
/**
@brief Measuring elapsed time in each frame
Measures time passed during specified sections of each frame. It's meant to be
used in rendering and event loops (e.g. Contexts::GlutContext::drawEvent()),
but it's possible to use it standalone elsewhere. Example usage:
@code
Profiler p;
// Register named sections
struct {
Profiler::Section ai, physics, draw, bufferSwap;
} sections;
sections.ai = p.addSection("AI");
sections.physics = p.addSection("Physics");
sections.draw = p.addSection("Drawing");
sections.bufferSwap = p.addSection("Buffer swap");
// Enable profiling
p.enable();
// Mark sections in draw function
void MyContext::drawEvent() {
p.start();
// ... misc stuff belogning to "Other" section
p.start(sections.ai);
// ... AI computation
p.start(sections.physics);
// ... physics simulation
p.start(sections.draw);
scene.draw()
p.start(sections.bufferSwap);
swapBuffers();
// Count everything before next call to drawEvent() into "Other" section
p.start();
// Mark start of next frame
p.nextFrame();
}
// Print statistics to debug output, showing how much time each section took
p.printStatistics();
@endcode
It's possible to start profiler only for certain parts of the code and then
stop it again using stop(), if you are not interested in profiling the rest.
@todo Some unit testing
@todo More time intervals
*/
class MAGNUM_EXPORT Profiler {
public:
/**
* @brief Section ID
*
* @see otherSection, addSection(), start(Section)
*/
typedef unsigned int Section;
/**
* @brief Default section
*
* @see start()
*/
static const Section otherSection = 0;
#ifndef DOXYGEN_GENERATING_OUTPUT
Profiler(): enabled(false), measureDuration(60), currentFrame(0), frameCount(0), sections{"Other"}, currentSection(otherSection) {}
#endif
/**
* @brief Set measure duration
*
* Measured data are averaged through given frame count. Default value
* is 60.
* @attention This function cannot be called if profiling is enabled.
*/
void setMeasureDuration(size_t frames);
/**
* @brief Add named section
*
* @attention This function cannot be called if profiling is enabled.
* @see otherSection, start(Section), stop()
*/
Section addSection(const std::string& name);
/**
* @brief Whether profiling is enabled
*
* If the profiling is not enabled, calls to start() and stop() have
* no effect.
*/
bool isEnabled() { return enabled; }
/**
* @brief Enable profiling
*
* Clears already mesaured data.
* @see disable(), isEnabled()
*/
void enable();
/**
* @brief Disable profiling
*
* @see enable(), isEnabled()
*/
void disable();
/**
* @brief Start profiling of given named section
*
* If profiling is already running, current time is saved for previous
* section.
* @see @ref otherSection, start(Section)
*/
void start(Section section);
/**
* @brief Start profiling of "other" section
*
* Same as calling `start(Profiler::otherSection)`.
* @note Does nothing if profiling is disabled.
*/
inline void start() { start(otherSection); }
/**
* @brief Stop profiling
*
* Current time is saved for previous section.
* @note Does nothing if profiling is disabled.
*/
void stop();
/**
* @brief Save data from previous frame and advance to another
*
* Call at the end of each frame.
* @note Does nothing if profiling is disabled.
*/
void nextFrame();
/**
* @brief Print statistics
*
* Prints statistics about previous frame ordered by duration.
* @note Does nothing if profiling is disabled.
*/
void printStatistics();
private:
void save();
bool enabled;
size_t measureDuration, currentFrame, frameCount;
std::vector<std::string> sections;
std::vector<std::chrono::high_resolution_clock::duration> frameData;
std::vector<std::chrono::high_resolution_clock::duration> totalData;
std::chrono::high_resolution_clock::time_point previousTime;
Section currentSection;
};
}
#endif
Loading…
Cancel
Save