Continue to work on the profiler

This commit is contained in:
Daniel Chappuis 2013-03-24 19:45:48 +01:00
parent 88e680e8e7
commit aa9bd2098d
5 changed files with 346 additions and 52 deletions

View File

@ -10,10 +10,15 @@ SET(LIBRARY_OUTPUT_PATH lib/)
# Options
OPTION(COMPILE_EXAMPLES "Select this if you want to build the examples" OFF)
OPTION(COMPILE_TESTS "Select this if you want to build the tests" OFF)
OPTION(PROFILING_ENABLED "Select this if you want to compile with enabled profiling" OFF)
# Headers
INCLUDE_DIRECTORIES(src)
IF (PROFILING_ENABLED)
ADD_DEFINITIONS(-DIS_PROFILING_ACTIVE)
ENDIF (PROFILING_ENABLED)
# Library configuration
file (
GLOB_RECURSE

View File

@ -1 +1,141 @@
/********************************************************************************
* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ *
* Copyright (c) 2010-2013 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
#ifdef IS_PROFILING_ACTIVE
// Libraries
#include "Profiler.h"
using namespace reactphysics3d;
// Initialization of static variables
ProfileNode Profiler::mRootNode("Root", NULL);
ProfileNode* Profiler::mCurrentNode = &Profiler::mRootNode;
uint Profiler::mFrameCounter = 0;
// Constructor
ProfileNode::ProfileNode(const char* name, ProfileNode* parentNode)
:mName(name), mNbTotalCalls(0), mStartingTime(0), mTotalTime(0),
mRecursionCounter(0), mParentNode(parentNode), mChildNode(NULL),
mSiblingNode(NULL) {
}
// Destructor
ProfileNode::~ProfileNode() {
delete mChildNode;
delete mSiblingNode;
}
// Return a pointer to a sub node with a given name
ProfileNode* ProfileNode::findSubNode(const char* name) {
// Try to find the node among the child nodes
ProfileNode* child = mChildNode;
while (child != NULL) {
if (child->mName == name) {
return child;
}
child = child->mSiblingNode;
}
// The nose has not been found. Therefore, we create it
// and add it to the profiler tree
ProfileNode* newNode = new ProfileNode(name, this);
newNode->mSiblingNode = child;
child = newNode;
return newNode;
}
// Called when we enter the block of code corresponding to this profile node
void ProfileNode::enterBlockOfCode() {
mNbTotalCalls++;
// If the current code is not called recursively
if (mRecursionCounter == 0) {
// Get the current system time to initialize the starting time of
// the profiling of the current block of code
mStartingTime = Timer::getCurrentSystemTime();
}
mRecursionCounter++;
}
// Called when we exit the block of code corresponding to this profile node
bool ProfileNode::exitBlockOfCode() {
mRecursionCounter--;
if (mRecursionCounter == 0 && mNbTotalCalls != 0) {
// Get the current system time
long double currentTime = Timer::getCurrentSystemTime();
// Increase the total elasped time in the current block of code
mTotalTime += currentTime - mStartingTime;
}
// Return true if the current code is not recursing
return (mRecursionCounter == 0);
}
// Method called when we want to start profiling a block of code.
void Profiler::startProfilingBlock(const char* name) {
// Look for the node in the tree that corresponds to the block of
// code to profile
if (name != mCurrentNode->getName()) {
mCurrentNode = mCurrentNode->findSubNode(name);
}
// Start profile the node
mCurrentNode->enterBlockOfCode();
}
// Method called at the end of the scope where the
// startProfilingBlock() method has been called.
void Profiler::stopProfilingBlock() {
// Go to the parent node unless if the current block
// of code is recursing
if (mCurrentNode->exitBlockOfCode()) {
mCurrentNode = mCurrentNode->getParentNode();
}
}
// Return an iterator over the profiler tree starting at the root
ProfileNodeIterator* Profiler::getIterator() {
return new ProfileNodeIterator(&mRootNode);
}
// Print the report of the profiler in a given output stream
void printReport(std::ostream& outputStream) {
}
#endif

View File

@ -26,7 +26,146 @@
#ifndef PROFILER_H
#define PROFILER_H
#ifdef IS_PROFILING_ACTIVE
// Libraries
#include "../configuration.h"
#include "Timer.h"
/// ReactPhysics3D namespace
namespace reactphysics3d {
// Class ProfileNode
/**
* It represents a profile sample in the profiler tree.
*/
class ProfileNode {
private :
/// Name of the node
const char* mName;
/// Total number of calls of this node
uint mNbTotalCalls;
/// Starting time of the sampling of corresponding block of code
long double mStartingTime;
/// Total time spent in the block of code
long double mTotalTime;
/// Recursion counter
int mRecursionCounter;
/// Pointer to the parent node
ProfileNode* mParentNode;
/// Pointer to a child node
ProfileNode* mChildNode;
/// Pointer to a sibling node
ProfileNode* mSiblingNode;
public :
/// Constructor
ProfileNode(const char* name, ProfileNode* parentNode);
/// Destructor
~ProfileNode();
/// Return a pointer to a sub node
ProfileNode* findSubNode(const char* name);
/// Return a pointer to the parent node
ProfileNode* getParentNode();
/// Return a pointer to a sibling node
ProfileNode* getSiblingNode();
/// Return a pointer to a child node
ProfileNode* getChildNode();
/// Return the name of the node
const char* getName();
/// Return the total number of call of the corresponding block of code
uint getNbTotalCalls() const;
/// Return the total time spent in the block of code
long double getTotalTime() const;
/// Called when we enter the block of code corresponding to this profile node
void enterBlockOfCode();
/// Called when we exit the block of code corresponding to this profile node
bool exitBlockOfCode();
};
// Class ProfileNodeIterator
/**
* This class allow us to iterator over the profiler tree.
*/
class ProfileNodeIterator {
private :
/// Current parent node
ProfileNode* mCurrentParent;
/// Current child node
ProfileNode* mCurrentChild;
public :
/// Constructor
ProfileNodeIterator(ProfileNode* startingNode);
/// Go to the first node
void first();
/// Go to the next node
void next();
/// Enter a given child node
void enterChild();
};
// Class Profiler
/**
* This is the main class of the profiler. This profiler is based on "Real-Time Hierarchical
* Profiling" article from "Game Programming Gems 3" by Greg Hjelstrom and Byon Garrabrant.
*/
class Profiler {
private :
/// Root node of the profiler tree
static ProfileNode mRootNode;
/// Current node in the current execution
static ProfileNode* mCurrentNode;
/// Frame counter
static uint mFrameCounter;
public :
/// Method called when we want to start profiling a block of code.
static void startProfilingBlock(const char *name);
/// Method called at the end of the scope where the
/// startProfilingBlock() method has been called.
static void stopProfilingBlock();
/// Return an iterator over the profiler tree starting at the root
static ProfileNodeIterator* getIterator();
/// Print the report of the profiler in a given output stream
static void printReport(std::ostream& outputStream);
};
// Class ProfileSample
/**
@ -42,7 +181,7 @@ class ProfileSample {
ProfileSample(const char* name) {
// Ask the profiler to start profiling a block of code
Profiler::startProfilingBlock();
Profiler::startProfilingBlock(name);
}
/// Destructor
@ -56,32 +195,43 @@ class ProfileSample {
/// Use this macro to start profile a block of code
#define PROFILE(name) ProfileSample profileSample(name)
// Class ProfileNode
/**
* Node of the profiler tree
*/
class ProfileNode {
/// Return a pointer to the parent node
ProfileNode* ProfileNode::getParentNode() {
return mParentNode;
}
};
/// Return a pointer to a sibling node
ProfileNode* ProfileNode::getSiblingNode() {
return mSiblingNode;
}
// Class Profiler
/**
* This is the main class of the profiler
*/
class Profiler {
/// Return a pointer to a child node
ProfileNode* ProfileNode::getChildNode() {
return mChildNode;
}
public :
/// Return the name of the node
const char* ProfileNode::getName() {
return mName;
}
/// Method called when we want to start profiling a block of code.
static void startProfilingBlock() {
/// Return the total number of call of the corresponding block of code
uint ProfileNode::getNbTotalCalls() const {
return mNbTotalCalls;
}
}
/// Return the total time spent in the block of code
long double ProfileNode::getTotalTime() const {
return mTotalTime;
}
/// Method called at the end of the scope where the startProfilingBlock() method
/// has been called.
static void stopProfilingBlock() {
}
}
};
#else // In profile is not active
// Empty macro in case profiling is not active
#define PROFILE(name)
#endif
#endif

View File

@ -39,6 +39,23 @@ Timer::~Timer() {
}
// Return the current time of the system
long double Timer::getCurrentSystemTime() {
#if defined(WINDOWS_OS)
LARGE_INTEGER ticksPerSecond;
LARGE_INTEGER ticks;
QueryPerformanceFrequency(&ticksPerSecond);
QueryPerformanceCounter(&ticks);
return (long double(ticks.QuadPart) / long double(ticksPerSecond.QuadPart));
#else
// Initialize the lastUpdateTime with the current time in seconds
timeval timeValue;
gettimeofday(&timeValue, NULL);
return (timeValue.tv_sec + (timeValue.tv_usec / 1000000.0));
#endif
}

View File

@ -74,6 +74,7 @@ class Timer {
/// True if the timer is running
bool mIsRunning;
// -------------------- Methods -------------------- //
/// Private copy-constructor
@ -98,8 +99,8 @@ class Timer {
/// Set the timestep of the physics engine
void setTimeStep(double timeStep);
/// Return the current time
long double getTime() const;
/// Return the current time of the physics engine
long double getPhysicsTime() const;
/// Start the timer
void start();
@ -121,6 +122,9 @@ class Timer {
/// Compute the interpolation factor
decimal computeInterpolationFactor();
/// Return the current time of the system
static long double getCurrentSystemTime();
};
// Return the timestep of the physics engine
@ -135,7 +139,7 @@ inline void Timer::setTimeStep(double timeStep) {
}
// Return the current time
inline long double Timer::getTime() const {
inline long double Timer::getPhysicsTime() const {
return mTime;
}
@ -147,19 +151,9 @@ inline bool Timer::getIsRunning() const {
// Start the timer
inline void Timer::start() {
if (!mIsRunning) {
#if defined(WINDOWS_OS)
LARGE_INTEGER ticksPerSecond;
LARGE_INTEGER ticks;
QueryPerformanceFrequency(&ticksPerSecond);
QueryPerformanceCounter(&ticks);
mLastUpdateTime = double(ticks.QuadPart) / double(ticksPerSecond.QuadPart);
#else
// Initialize the lastUpdateTime with the current time in seconds
timeval timeValue;
gettimeofday(&timeValue, NULL);
mLastUpdateTime = timeValue.tv_sec + (timeValue.tv_usec / 1000000.0);
#endif
// Get the current system time
mLastUpdateTime = getCurrentSystemTime();
mAccumulator = 0.0;
mIsRunning = true;
@ -168,7 +162,6 @@ inline void Timer::start() {
// Stop the timer
inline void Timer::stop() {
std::cout << "Timer stop" << std::endl;
mIsRunning = false;
}
@ -195,20 +188,9 @@ inline decimal Timer::computeInterpolationFactor() {
// Compute the time since the last update() call and add it to the accumulator
inline void Timer::update() {
long double currentTime;
#if defined(WINDOWS_OS)
LARGE_INTEGER ticksPerSecond;
LARGE_INTEGER ticks;
QueryPerformanceFrequency(&ticksPerSecond);
QueryPerformanceCounter(&ticks);
currentTime = double(ticks.QuadPart) / double(ticksPerSecond.QuadPart);
#else
// Compute the current time is seconds
timeval timeValue;
gettimeofday(&timeValue, NULL);
currentTime = timeValue.tv_sec + (timeValue.tv_usec / 1000000.0);
#endif
// Get the current system time
long double currentTime = getCurrentSystemTime();
// Compute the delta display time between two display frames
mDeltaTime = currentTime - mLastUpdateTime;