-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement System::TimeProfiler (#826)
The original code has been taken from https://github.com/robotology/walking-controllers/tree/edc8984998043c98182f726e17822deb2a7b1915/src/TimeProfiler - -------- Co-authored-by: Giulio Romualdi <[email protected]>
- Loading branch information
1 parent
4e9a2ba
commit add39bb
Showing
4 changed files
with
220 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
src/System/include/BipedalLocomotion/System/TimeProfiler.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* @file TimeProfiler.h | ||
* @authors Guglielmo Cervettini, Giulio Romualdi | ||
* @copyright 2024 Istituto Italiano di Tecnologia (IIT). This software may be modified and | ||
* distributed under the terms of the BSD-3-Clause license. | ||
*/ | ||
|
||
#ifndef BIPEDAL_LOCOMOTION_SYSTEM_TIME_PROFILER_H | ||
#define BIPEDAL_LOCOMOTION_SYSTEM_TIME_PROFILER_H | ||
|
||
// std | ||
#include <chrono> | ||
#include <map> | ||
#include <memory> | ||
|
||
namespace BipedalLocomotion | ||
{ | ||
namespace System | ||
{ | ||
/** | ||
* Timer is a simple class that can be used to measure the time between two events. | ||
*/ | ||
class Timer | ||
{ | ||
std::chrono::time_point<std::chrono::steady_clock> m_initTime; /**< Init time. */ | ||
std::chrono::time_point<std::chrono::steady_clock> m_endTime; /**< End time. */ | ||
std::chrono::nanoseconds m_averageDuration; /**< Average duration. */ | ||
|
||
public: | ||
/** | ||
* Reset the average duration. | ||
*/ | ||
void resetAverageDuration(); | ||
|
||
/** | ||
* Set initial time. | ||
*/ | ||
void setInitTime(); | ||
|
||
/** | ||
* Set final time. | ||
*/ | ||
void setEndTime(); | ||
|
||
/** | ||
* Evaluate the average duration. | ||
*/ | ||
void evaluateDuration(); | ||
|
||
/** | ||
* Get the average duration. | ||
* @return average duration. | ||
*/ | ||
const std::chrono::nanoseconds& getAverageDuration() const; | ||
}; | ||
|
||
/** | ||
* TimeProfiler is a simple class that can be used to profile the code. | ||
*/ | ||
class TimeProfiler | ||
{ | ||
int m_counter; /**< Counter useful to print the profiling quantities only every m_maxCounter | ||
times. */ | ||
int m_maxCounter; /**< The profiling quantities will be printed every maxCounter cycles. */ | ||
std::map<std::string, Timer> m_timers; /**< Dictionary that contains all the timers. */ | ||
public: | ||
/** | ||
* Set the output period. | ||
* @param maxCounter is the period (expressed in cycles). | ||
*/ | ||
void setPeriod(int maxCounter); | ||
|
||
/** | ||
* Add a new timer | ||
* @param key is the name of the timer. | ||
* @return true/false in case of success/failure. | ||
*/ | ||
bool addTimer(const std::string& key); | ||
|
||
/** | ||
* Set the init time for the timer named "key" | ||
* @param key is the name of the timer. | ||
* @return true/false in case of success/failure. | ||
*/ | ||
bool setInitTime(const std::string& key); | ||
|
||
/** | ||
* Set the end time for the timer named "key" | ||
* @param key is the name of the timer. | ||
* @return true/false in case of success/failure. | ||
*/ | ||
bool setEndTime(const std::string& key); | ||
|
||
/** | ||
* Print the profiling quantities. | ||
*/ | ||
void profiling(); | ||
}; | ||
|
||
}; // namespace System | ||
}; // namespace BipedalLocomotion | ||
|
||
#endif // BIPEDAL_LOCOMOTION_SYSTEM_TIME_PROFILER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/** | ||
* @file TimeProfiler.cpp | ||
* @authors Guglielmo Cervettini, Giulio Romualdi | ||
* @copyright 2024 Istituto Italiano di Tecnologia (IIT). This software may be modified and | ||
* distributed under the terms of the BSD-3-Clause license. | ||
*/ | ||
|
||
#include <chrono> | ||
#include <string> | ||
|
||
#include <BipedalLocomotion/System/TimeProfiler.h> | ||
#include <BipedalLocomotion/TextLogging/Logger.h> | ||
|
||
using namespace BipedalLocomotion::System; | ||
|
||
const std::chrono::nanoseconds& Timer::getAverageDuration() const | ||
{ | ||
return m_averageDuration; | ||
} | ||
|
||
void Timer::resetAverageDuration() | ||
{ | ||
m_averageDuration = std::chrono::nanoseconds(0); | ||
} | ||
|
||
void Timer::setInitTime() | ||
{ | ||
m_initTime = std::chrono::steady_clock::now(); | ||
} | ||
|
||
void Timer::setEndTime() | ||
{ | ||
m_endTime = std::chrono::steady_clock::now(); | ||
} | ||
|
||
void Timer::evaluateDuration() | ||
{ | ||
const std::chrono::nanoseconds duration = m_endTime - m_initTime; | ||
m_averageDuration += duration; | ||
} | ||
|
||
void TimeProfiler::setPeriod(int maxCounter) | ||
{ | ||
m_maxCounter = maxCounter; | ||
} | ||
|
||
bool TimeProfiler::addTimer(const std::string& key) | ||
{ | ||
auto timer = m_timers.find(key); | ||
if (timer != m_timers.end()) | ||
{ | ||
log()->error("[TimeProfiler::addTimer] The timer named {} already exists.", key); | ||
return false; | ||
} | ||
|
||
m_timers.insert(std::make_pair(key, Timer())); | ||
return true; | ||
} | ||
|
||
bool TimeProfiler::setInitTime(const std::string& key) | ||
{ | ||
auto timer = m_timers.find(key); | ||
if (timer == m_timers.end()) | ||
{ | ||
log()->error("[TimeProfiler::setInitTime] Unable to find the timer named {}.", key); | ||
return false; | ||
} | ||
|
||
timer->second.setInitTime(); | ||
return true; | ||
} | ||
|
||
bool TimeProfiler::setEndTime(const std::string& key) | ||
{ | ||
auto timer = m_timers.find(key); | ||
if (timer == m_timers.end()) | ||
{ | ||
log()->error("[TimeProfiler::setEndTime] Unable to find the timer named {}.", key); | ||
return false; | ||
} | ||
|
||
timer->second.setEndTime(); | ||
return true; | ||
} | ||
|
||
void TimeProfiler::profiling() | ||
{ | ||
std::string infoStream; | ||
m_counter++; | ||
for (auto& [key, timer] : m_timers) | ||
{ | ||
timer.evaluateDuration(); | ||
if (m_counter != m_maxCounter) | ||
{ | ||
continue; | ||
} | ||
|
||
const std::chrono::nanoseconds& durationInNs = timer.getAverageDuration(); | ||
|
||
// convert the duration in ns to ms | ||
const auto durationInMs | ||
= std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(durationInNs) | ||
/ double(m_counter); | ||
|
||
infoStream += key + ": " + std::to_string(durationInMs.count()) + " ms "; | ||
timer.resetAverageDuration(); | ||
} | ||
|
||
if (m_counter == m_maxCounter) | ||
{ | ||
m_counter = 0; | ||
log()->info("[TimeProfiler::profiling] {}", infoStream); | ||
} | ||
} |