Go to the documentation of this file.00001 #ifndef SWRI_PROFILER_PROFILER_H_
00002 #define SWRI_PROFILER_PROFILER_H_
00003
00004 #include <algorithm>
00005 #include <limits>
00006 #include <unordered_map>
00007 #include <atomic>
00008
00009 #include <ros/time.h>
00010 #include <ros/console.h>
00011 #include <diagnostic_updater/diagnostic_updater.h>
00012
00013 namespace swri_profiler
00014 {
00015 class SpinLock
00016 {
00017 std::atomic_flag locked_;
00018 public:
00019 SpinLock() : locked_(ATOMIC_FLAG_INIT) {}
00020
00021 void acquire()
00022 {
00023 while (locked_.test_and_set(std::memory_order_acquire)) { ; }
00024 }
00025
00026 void release()
00027 {
00028 locked_.clear(std::memory_order_release);
00029 }
00030 };
00031
00032 class SpinLockGuard
00033 {
00034 SpinLock &lock_;
00035
00036 public:
00037 SpinLockGuard(SpinLock &lock) : lock_(lock) { lock_.acquire(); }
00038 ~SpinLockGuard() { lock_.release(); }
00039 };
00040
00041 class Profiler
00042 {
00043
00044
00045 struct OpenInfo
00046 {
00047 ros::WallTime t0;
00048 ros::WallTime last_report_time;
00049 OpenInfo() : last_report_time(0) {}
00050 };
00051
00052
00053
00054 struct ClosedInfo
00055 {
00056 size_t count;
00057 ros::WallDuration total_duration;
00058 ros::WallDuration rel_duration;
00059 ros::WallDuration max_duration;
00060 ClosedInfo() : count(0) {}
00061 };
00062
00063
00064 struct TLS
00065 {
00066
00067
00068
00069 size_t stack_depth;
00070 std::string stack_str;
00071 std::string thread_prefix;
00072 };
00073
00074
00075
00076
00077
00078 static std::unordered_map<std::string, OpenInfo> open_blocks_;
00079
00080
00081
00082
00083 static std::unordered_map<std::string, ClosedInfo> closed_blocks_;
00084
00085
00086
00087 static boost::thread_specific_ptr<TLS> tls_;
00088
00089
00090 static SpinLock lock_;
00091
00092
00093 static void initializeProfiler();
00094 static void initializeTLS();
00095 static void profilerMain();
00096 static void collectAndPublish();
00097
00098 static bool open(const std::string &name, const ros::WallTime &t0)
00099 {
00100 if (!tls_.get()) { initializeTLS(); }
00101
00102 if (name.empty()) {
00103 ROS_ERROR("Profiler error: Profiled section has empty name. "
00104 "Current stack is '%s'.",
00105 tls_->stack_str.c_str());
00106 return false;
00107 }
00108
00109 if (tls_->stack_depth >= 100) {
00110 ROS_ERROR("Profiler error: reached max stack size (%zu) while "
00111 "opening '%s'. Current stack is '%s'.",
00112 tls_->stack_depth,
00113 name.c_str(),
00114 tls_->stack_str.c_str());
00115 return false;
00116 }
00117
00118 tls_->stack_depth++;
00119 tls_->stack_str = tls_->stack_str + "/" + name;
00120
00121 std::string open_index = tls_->thread_prefix + tls_->stack_str;
00122 {
00123 SpinLockGuard guard(lock_);
00124 OpenInfo &info = open_blocks_[open_index];
00125 info.t0 = t0;
00126 info.last_report_time = ros::WallTime(0,0);
00127 }
00128
00129 return true;
00130 }
00131
00132 static void close(const std::string &name, const ros::WallTime &tf)
00133 {
00134 std::string open_index = tls_->thread_prefix + tls_->stack_str;
00135 {
00136 SpinLockGuard guard(lock_);
00137
00138 auto const open_it = open_blocks_.find(open_index);
00139 if (open_it == open_blocks_.end()) {
00140 ROS_ERROR("Missing entry for '%s' in open_index. Profiler is probably corrupted.",
00141 name.c_str());
00142 return;
00143 }
00144
00145 ros::WallDuration abs_duration = tf - open_it->second.t0;
00146 ros::WallDuration rel_duration;
00147 if (open_it->second.last_report_time > open_it->second.t0) {
00148 rel_duration = tf - open_it->second.last_report_time;
00149 } else {
00150 rel_duration = tf - open_it->second.t0;
00151 }
00152 open_blocks_.erase(open_it);
00153
00154 ClosedInfo &info = closed_blocks_[tls_->stack_str];
00155 info.count++;
00156 if (info.count == 1) {
00157 info.total_duration = abs_duration;
00158 info.max_duration = abs_duration;
00159 info.rel_duration = rel_duration;
00160 } else {
00161 info.total_duration += abs_duration;
00162 info.rel_duration += rel_duration;
00163 info.max_duration = std::max(info.max_duration, abs_duration);
00164 }
00165 }
00166
00167 const size_t len = name.size()+1;
00168 tls_->stack_str.erase(tls_->stack_str.size()-len, len);
00169 tls_->stack_depth--;
00170 }
00171
00172 private:
00173 std::string name_;
00174
00175 public:
00176 Profiler(const std::string &name)
00177 {
00178 if (open(name, ros::WallTime::now())) {
00179 name_ = name;
00180 } else {
00181 name_ = "";
00182 }
00183 }
00184
00185 ~Profiler()
00186 {
00187 if (!name_.empty()) {
00188 close(name_, ros::WallTime::now());
00189 }
00190 }
00191 };
00192 }
00193
00194
00195 #define SWRI_PROFILER_CONCAT_DIRECT(s1,s2) s1##s2
00196 #define SWRI_PROFILER_CONCAT(s1, s2) SWRI_PROFILER_CONCAT_DIRECT(s1,s2)
00197
00198 #define SWRI_PROFILER_IMP(block_var, name) \
00199 swri_profiler::Profiler block_var(name); \
00200
00201 #ifndef DISABLE_SWRI_PROFILER
00202 #define SWRI_PROFILE(name) SWRI_PROFILER_IMP( \
00203 SWRI_PROFILER_CONCAT(prof_block_, __LINE__), \
00204 name)
00205 #else // ndef DISABLE_SWRI_PROFILER
00206 #define SWRI_PROFILE(name)
00207 #endif // def DISABLE_SWRI_PROFILER
00208
00209 #endif // SWRI_PROFILER_PROFILER_H_