Go to the documentation of this file.00001 #include <ros/this_node.h>
00002 #include <swri_profiler/profiler.h>
00003 #include <ros/publisher.h>
00004
00005 #include <swri_profiler_msgs/ProfileIndex.h>
00006 #include <swri_profiler_msgs/ProfileIndexArray.h>
00007 #include <swri_profiler_msgs/ProfileData.h>
00008 #include <swri_profiler_msgs/ProfileDataArray.h>
00009
00010 namespace spm = swri_profiler_msgs;
00011
00012 namespace swri_profiler
00013 {
00014
00015 std::unordered_map<std::string, Profiler::ClosedInfo> Profiler::closed_blocks_;
00016 std::unordered_map<std::string, Profiler::OpenInfo> Profiler::open_blocks_;
00017 boost::thread_specific_ptr<Profiler::TLS> Profiler::tls_;
00018 SpinLock Profiler::lock_;
00019
00020
00021
00022
00023
00024 static bool profiler_initialized_ = false;
00025 static ros::Publisher profiler_index_pub_;
00026 static ros::Publisher profiler_data_pub_;
00027 static boost::thread profiler_thread_;
00028
00029
00030
00031
00032
00033 static std::unordered_map<std::string, spm::ProfileData> all_closed_blocks_;
00034
00035 static ros::Duration durationFromWall(const ros::WallDuration &src)
00036 {
00037 return ros::Duration(src.sec, src.nsec);
00038 }
00039
00040 static ros::Time timeFromWall(const ros::WallTime &src)
00041 {
00042 return ros::Time(src.sec, src.nsec);
00043 }
00044
00045 void Profiler::initializeProfiler()
00046 {
00047 SpinLockGuard guard(lock_);
00048 if (profiler_initialized_) {
00049 return;
00050 }
00051
00052 ROS_INFO("Initializing swri_profiler...");
00053 ros::NodeHandle nh;
00054 profiler_index_pub_ = nh.advertise<spm::ProfileIndexArray>("/profiler/index", 1, true);
00055 profiler_data_pub_ = nh.advertise<spm::ProfileDataArray>("/profiler/data", 100, false);
00056 profiler_thread_ = boost::thread(Profiler::profilerMain);
00057 profiler_initialized_ = true;
00058 }
00059
00060 void Profiler::initializeTLS()
00061 {
00062 if (tls_.get()) {
00063 ROS_ERROR("Attempt to initialize thread local storage again.");
00064 return;
00065 }
00066
00067 tls_.reset(new TLS());
00068 tls_->stack_depth = 0;
00069 tls_->stack_str = "";
00070
00071 char buffer[256];
00072 snprintf(buffer, sizeof(buffer), "%p/", tls_.get());
00073 tls_->thread_prefix = std::string(buffer);
00074
00075 initializeProfiler();
00076 }
00077
00078 void Profiler::profilerMain()
00079 {
00080 ROS_DEBUG("swri_profiler thread started.");
00081 while (ros::ok()) {
00082
00083 ros::WallTime now = ros::WallTime::now();
00084 ros::WallTime next(now.sec+1,0);
00085 (next-now).sleep();
00086 collectAndPublish();
00087 }
00088
00089 ROS_DEBUG("swri_profiler thread stopped.");
00090 }
00091
00092 void Profiler::collectAndPublish()
00093 {
00094 static bool first_run = true;
00095 static ros::WallTime last_now = ros::WallTime::now();
00096
00097
00098 std::unordered_map<std::string, ClosedInfo> new_closed_blocks;
00099 std::unordered_map<std::string, OpenInfo> threaded_open_blocks;
00100 ros::WallTime now = ros::WallTime::now();
00101 ros::Time ros_now = ros::Time::now();
00102 {
00103 SpinLockGuard guard(lock_);
00104 new_closed_blocks.swap(closed_blocks_);
00105 for (auto &pair : open_blocks_) {
00106 threaded_open_blocks[pair.first].t0 = pair.second.t0;
00107 pair.second.last_report_time = now;
00108 }
00109 }
00110
00111
00112 for (auto &pair : all_closed_blocks_) {
00113 pair.second.rel_total_duration = ros::Duration(0);
00114 pair.second.rel_max_duration = ros::Duration(0);
00115 }
00116
00117
00118 bool update_index = false;
00119
00120
00121 for (auto const &pair : new_closed_blocks) {
00122 const auto &label = pair.first;
00123 const auto &new_info = pair.second;
00124
00125 auto &all_info = all_closed_blocks_[label];
00126
00127 if (all_info.key == 0) {
00128 update_index = true;
00129 all_info.key = all_closed_blocks_.size();
00130 }
00131
00132 all_info.abs_call_count += new_info.count;
00133 all_info.abs_total_duration += durationFromWall(new_info.total_duration);
00134 all_info.rel_total_duration += durationFromWall(new_info.rel_duration);
00135 all_info.rel_max_duration = std::max(all_info.rel_max_duration,
00136 durationFromWall(new_info.max_duration));
00137 }
00138
00139
00140
00141 std::unordered_map<std::string, spm::ProfileData> combined_open_blocks;
00142 for (auto const &pair : threaded_open_blocks) {
00143 const auto &threaded_label = pair.first;
00144 const auto &threaded_info = pair.second;
00145
00146 size_t slash_index = threaded_label.find('/');
00147 if (slash_index == std::string::npos) {
00148 ROS_ERROR("Missing expected slash in label: %s", threaded_label.c_str());
00149 continue;
00150 }
00151
00152 ros::Duration duration = durationFromWall(now - threaded_info.t0);
00153
00154 const auto label = threaded_label.substr(slash_index+1);
00155 auto &new_info = combined_open_blocks[label];
00156
00157 if (new_info.key == 0) {
00158 auto &all_info = all_closed_blocks_[label];
00159 if (all_info.key == 0) {
00160 update_index = true;
00161 all_info.key = all_closed_blocks_.size();
00162 }
00163 new_info.key = all_info.key;
00164 }
00165
00166 new_info.abs_call_count++;
00167 new_info.abs_total_duration += duration;
00168 if (first_run) {
00169 new_info.rel_total_duration += duration;
00170 } else {
00171 new_info.rel_total_duration += std::min(
00172 durationFromWall(now - last_now), duration);
00173 }
00174 new_info.rel_max_duration = std::max(new_info.rel_max_duration, duration);
00175 }
00176
00177 if (update_index) {
00178 spm::ProfileIndexArray index;
00179 index.header.stamp = timeFromWall(now);
00180 index.header.frame_id = ros::this_node::getName();
00181 index.data.resize(all_closed_blocks_.size());
00182
00183 for (auto const &pair : all_closed_blocks_) {
00184 size_t i = pair.second.key - 1;
00185 index.data[i].key = pair.second.key;
00186 index.data[i].label = pair.first;
00187 }
00188 profiler_index_pub_.publish(index);
00189 }
00190
00191
00192 spm::ProfileDataArray msg;
00193 msg.header.stamp = timeFromWall(now);
00194 msg.header.frame_id = ros::this_node::getName();
00195 msg.rostime_stamp = ros_now;
00196
00197 msg.data.resize(all_closed_blocks_.size());
00198 for (auto &pair : all_closed_blocks_) {
00199 auto const &item = pair.second;
00200 size_t i = item.key - 1;
00201
00202 msg.data[i].key = item.key;
00203 msg.data[i].abs_call_count = item.abs_call_count;
00204 msg.data[i].abs_total_duration = item.abs_total_duration;
00205 msg.data[i].rel_total_duration = item.rel_total_duration;
00206 msg.data[i].rel_max_duration = item.rel_max_duration;
00207 }
00208
00209 for (auto &pair : combined_open_blocks) {
00210 auto const &item = pair.second;
00211 size_t i = item.key - 1;
00212 msg.data[i].abs_call_count += item.abs_call_count;
00213 msg.data[i].abs_total_duration += item.abs_total_duration;
00214 msg.data[i].rel_total_duration += item.rel_total_duration;
00215 msg.data[i].rel_max_duration = std::max(
00216 msg.data[i].rel_max_duration,
00217 item.rel_max_duration);
00218 }
00219
00220 profiler_data_pub_.publish(msg);
00221 first_run = false;
00222 last_now = now;
00223 }
00224 }