gtsam/gtsam/base/timing.h

329 lines
9.6 KiB
C++

/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file timing.h
* @brief
* @author Richard Roberts, Michael Kaess
* @created Oct 5, 2010
*/
#pragma once
#include <gtsam/base/debug.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <sys/time.h>
#include <map>
#include <stdlib.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
class TimingOutline;
extern boost::shared_ptr<TimingOutline> timingRoot;
extern boost::weak_ptr<TimingOutline> timingCurrent;
class TimingOutline {
protected:
size_t t_;
size_t tIt_;
size_t tMax_;
size_t tMin_;
size_t n_;
std::string label_;
boost::weak_ptr<TimingOutline> parent_;
std::vector<boost::shared_ptr<TimingOutline> > children_;
struct timeval t0_;
bool timerActive_;
inline void add(size_t usecs) {
t_ += usecs;
tIt_ += usecs;
++ n_;
}
public:
inline TimingOutline(const std::string& label) :
t_(0), tIt_(0), tMax_(0), tMin_(0), n_(0), label_(label), timerActive_(false) {}
inline size_t time() const {
size_t time = 0;
bool hasChildren = false;
BOOST_FOREACH(const boost::shared_ptr<TimingOutline>& child, children_) {
if(child) {
time += child->time();
hasChildren = true;
}
}
if(hasChildren)
return time;
else
return t_;
}
inline void print(const std::string& outline = "") const {
std::cout << outline << " " << label_ << ": " << double(t_)/1000000.0 << " (" <<
n_ << " times, " << double(time())/1000000.0 << " children, min: " << double(tMin_)/1000000.0 <<
" max: " << double(tMax_)/1000000.0 << ")\n";
for(size_t i=0; i<children_.size(); ++i) {
if(children_[i]) {
std::string childOutline(outline);
#if 0
if(childOutline.size() > 0)
childOutline += ".";
childOutline += (boost::format("%d") % i).str();
#else
childOutline += " ";
#endif
children_[i]->print(childOutline);
}
}
}
inline const boost::shared_ptr<TimingOutline>& child(size_t child, const std::string& label, const boost::weak_ptr<TimingOutline>& thisPtr) {
assert(thisPtr.lock().get() == this);
// Resize if necessary
if(child >= children_.size())
children_.resize(child + 1);
// Create child if necessary
if(children_[child]) {
#ifndef NDEBUG
if(children_[child]->label_ != label) {
timingRoot->print();
std::cerr << "gtsam timing: tic called with id=" << child << ", label=" << label << ", but this id already has the label " << children_[child]->label_ << std::endl;
exit(1);
}
#endif
} else {
children_[child].reset(new TimingOutline(label));
children_[child]->parent_ = thisPtr;
}
return children_[child];
}
inline void tic() {
assert(!timerActive_);
timerActive_ = true;
gettimeofday(&t0_, NULL);
}
inline void toc() {
struct timeval t;
gettimeofday(&t, NULL);
assert(timerActive_);
add(t.tv_sec*1000000 + t.tv_usec - (t0_.tv_sec*1000000 + t0_.tv_usec));
timerActive_ = false;
}
inline void finishedIteration() {
if(tIt_ > tMax_)
tMax_ = tIt_;
if(tMin_ == 0 || tIt_ < tMin_)
tMin_ = tIt_;
tIt_ = 0;
for(size_t i=0; i<children_.size(); ++i)
if(children_[i])
children_[i]->finishedIteration();
}
friend class AutoTimer;
friend void toc_(size_t id);
friend void toc_(size_t id, const std::string& label);
};
inline void tic_(size_t id, const std::string& label) {
if(ISDEBUG("timing-verbose"))
std::cout << "tic(" << id << ", " << label << ")" << std::endl;
boost::shared_ptr<TimingOutline> node = timingCurrent.lock()->child(id, label, timingCurrent);
timingCurrent = node;
node->tic();
}
inline void toc_(size_t id) {
if(ISDEBUG("timing-verbose"))
std::cout << "toc(" << id << ")" << std::endl;
boost::shared_ptr<TimingOutline> current(timingCurrent.lock());
if(!(id < current->parent_.lock()->children_.size() && current->parent_.lock()->children_[id] == current)) {
std::cout << "gtsam timing: Incorrect ID passed to toc" << std::endl;
timingRoot->print();
throw std::invalid_argument("gtsam timing: Incorrect ID passed to toc");
}
current->toc();
if(!current->parent_.lock()) {
std::cout << "gtsam timing: extra toc, already at the root" << std::endl;
timingRoot->print();
throw std::invalid_argument("gtsam timing: extra toc, already at the root");
}
timingCurrent = current->parent_;
}
inline void toc_(size_t id, const std::string& label) {
if(ISDEBUG("timing-verbose"))
std::cout << "toc(" << id << ", " << label << ")" << std::endl;
#ifdef NDEBUG
// If NDEBUG is defined, still do this debug check if the granular debugging
// flag is enabled. If NDEBUG is not defined, always do this check.
if(ISDEBUG("timing-debug"))
#endif
{
if(label != timingCurrent.lock()->label_) {
std::cerr << "gtsam timing: toc called with id=" << id << ", label=\"" << label << "\", but expecting \"" << timingCurrent.lock()->label_ << "\"" << std::endl;
timingRoot->print();
exit(1);
}
}
toc_(id);
}
inline void tictoc_finishedIteration_() {
timingRoot->finishedIteration();
}
#ifdef ENABLE_TIMING
inline void tic(size_t id, const std::string& label) { tic_(id, label); }
inline void toc(size_t id) { toc_(id); }
inline void toc(size_t id, const std::string& label) { toc_(id, label); }
inline void tictoc_finishedIteration() { tictoc_finishedIteration_(); }
#else
inline void tic(size_t id, const std::string& label) {}
inline void toc(size_t id) {}
inline void toc(size_t id, const std::string& label) {}
inline void tictoc_finishedIteration() {}
#endif
// simple class for accumulating execution timing information by name
class Timing;
extern Timing timing;
extern std::string timingPrefix;
double _tic();
double _toc(double t);
double tic(const std::string& id);
double toc(const std::string& id);
void ticPush(const std::string& id);
void ticPop(const std::string& id);
void tictoc_print();
void tictoc_finishedIteration();
/** These underscore versions work evening when ENABLE_TIMING is not defined */
double _tic_();
double _toc_(double t);
double tic_(const std::string& id);
double toc_(const std::string& id);
void ticPush_(const std::string& id);
void ticPop_(const std::string& id);
void tictoc_print_();
void tictoc_finishedIteration_();
// simple class for accumulating execution timing information by name
class Timing {
class Stats {
public:
std::string label;
double t0;
double t;
double t_max;
double t_min;
int n;
};
std::map<std::string, Stats> stats;
public:
void add_t0(const std::string& id, double t0) {
stats[id].t0 = t0;
}
double get_t0(const std::string& id) {
return stats[id].t0;
}
void add_dt(const std::string& id, double dt) {
Stats& s = stats[id];
s.t += dt;
s.n++;
if (s.n==1 || s.t_max < dt) s.t_max = dt;
if (s.n==1 || s.t_min > dt) s.t_min = dt;
}
void print() {
std::map<std::string, Stats>::iterator it;
for(it = stats.begin(); it!=stats.end(); it++) {
Stats& s = it->second;
printf("%s: %g (%i times, min: %g, max: %g)\n",
it->first.c_str(), s.t, s.n, s.t_min, s.t_max);
}
}
double time(const std::string& id) {
Stats& s = stats[id];
return s.t;
}
};
inline double _tic_() {
struct timeval t;
gettimeofday(&t, NULL);
return ((double)t.tv_sec + ((double)t.tv_usec)/1000000.);
}
inline double _toc_(double t) {
double s = _tic_();
return (std::max(0., s-t));
}
inline double tic_(const std::string& id) {
double t0 = _tic_();
timing.add_t0(timingPrefix + " " + id, t0);
return t0;
}
inline double toc_(const std::string& id) {
std::string comb(timingPrefix + " " + id);
double dt = _toc_(timing.get_t0(comb));
timing.add_dt(comb, dt);
return dt;
}
inline void ticPush_(const std::string& prefix, const std::string& id) {
if(timingPrefix.size() > 0)
timingPrefix += ".";
timingPrefix += prefix;
tic_(id);
}
inline void ticPop_(const std::string& prefix, const std::string& id) {
toc_(id);
if(timingPrefix.size() < prefix.size()) {
fprintf(stderr, "Seems to be a mismatched push/pop in timing, exiting\n");
exit(1);
} else if(timingPrefix.size() == prefix.size())
timingPrefix.resize(0);
else
timingPrefix.resize(timingPrefix.size() - prefix.size() - 1);
}
inline void tictoc_print_() {
timing.print();
timingRoot->print();
}
#ifdef ENABLE_TIMING
inline double _tic() { return _tic_(); }
inline double _toc(double t) { return _toc_(t); }
inline double tic(const std::string& id) { return tic_(id); }
inline double toc(const std::string& id) { return toc_(id); }
inline void ticPush(const std::string& prefix, const std::string& id) { ticPush_(prefix, id); }
inline void ticPop(const std::string& prefix, const std::string& id) { ticPop_(prefix, id); }
inline void tictoc_print() { tictoc_print_(); }
#else
inline double _tic() {return 0.;}
inline double _toc(double t) {return 0.;}
inline double tic(const std::string& id) {return 0.;}
inline double toc(const std::string& id) {return 0.;}
inline void ticPush(const std::string& prefix, const std::string& id) {}
inline void ticPop(const std::string& prefix, const std::string& id) {}
inline void tictoc_print() {}
#endif