profiler.cpp
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 // Define/initialize static member variables for the Profiler class.
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 // Declare some more variables.  These are essentially more private
00021 // static members for the Profiler, but by using static global
00022 // variables instead we are able to keep more of the implementation
00023 // isolated.
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 // collectAndPublish resets the closed_blocks_ member after each
00030 // update to reduce the amount of copying done (which might block the
00031 // threads doing actual work).  The incremental snapshots are
00032 // collected here in all_closed_blocks_;
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     // Align updates to approximately every second.
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   // Grab a snapshot of the current state.  
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   // Reset all relative max durations.
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   // Flag to indicate if a new item was added.
00118   bool update_index = false;
00119 
00120   // Merge the new stats into the absolute stats
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   // Combine the open blocks from all threads into a single
00140   // map.
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   // Generate output message
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 }  // namespace swri_profiler


swri_profiler
Author(s):
autogenerated on Sat Apr 27 2019 03:08:47