profiler.cpp
Go to the documentation of this file.
1 #include <ros/this_node.h>
3 #include <ros/publisher.h>
4 
5 #include <swri_profiler_msgs/ProfileIndex.h>
6 #include <swri_profiler_msgs/ProfileIndexArray.h>
7 #include <swri_profiler_msgs/ProfileData.h>
8 #include <swri_profiler_msgs/ProfileDataArray.h>
9 
10 namespace spm = swri_profiler_msgs;
11 
12 namespace swri_profiler
13 {
14 // Define/initialize static member variables for the Profiler class.
15 std::unordered_map<std::string, Profiler::ClosedInfo> Profiler::closed_blocks_;
16 std::unordered_map<std::string, Profiler::OpenInfo> Profiler::open_blocks_;
17 boost::thread_specific_ptr<Profiler::TLS> Profiler::tls_;
18 SpinLock Profiler::lock_;
19 
20 // Declare some more variables. These are essentially more private
21 // static members for the Profiler, but by using static global
22 // variables instead we are able to keep more of the implementation
23 // isolated.
24 static bool profiler_initialized_ = false;
27 static boost::thread profiler_thread_;
28 
29 // collectAndPublish resets the closed_blocks_ member after each
30 // update to reduce the amount of copying done (which might block the
31 // threads doing actual work). The incremental snapshots are
32 // collected here in all_closed_blocks_;
33 static std::unordered_map<std::string, spm::ProfileData> all_closed_blocks_;
34 
36 {
37  return ros::Duration(src.sec, src.nsec);
38 }
39 
41 {
42  return ros::Time(src.sec, src.nsec);
43 }
44 
46 {
47  SpinLockGuard guard(lock_);
48  if (profiler_initialized_) {
49  return;
50  }
51 
52  ROS_INFO("Initializing swri_profiler...");
53  ros::NodeHandle nh;
54  profiler_index_pub_ = nh.advertise<spm::ProfileIndexArray>("/profiler/index", 1, true);
55  profiler_data_pub_ = nh.advertise<spm::ProfileDataArray>("/profiler/data", 100, false);
56  profiler_thread_ = boost::thread(Profiler::profilerMain);
57  profiler_initialized_ = true;
58 }
59 
61 {
62  if (tls_.get()) {
63  ROS_ERROR("Attempt to initialize thread local storage again.");
64  return;
65  }
66 
67  tls_.reset(new TLS());
68  tls_->stack_depth = 0;
69  tls_->stack_str = "";
70 
71  char buffer[256];
72  snprintf(buffer, sizeof(buffer), "%p/", tls_.get());
73  tls_->thread_prefix = std::string(buffer);
74 
76 }
77 
79 {
80  ROS_DEBUG("swri_profiler thread started.");
81  while (ros::ok()) {
82  // Align updates to approximately every second.
84  ros::WallTime next(now.sec+1,0);
85  (next-now).sleep();
87  }
88 
89  ROS_DEBUG("swri_profiler thread stopped.");
90 }
91 
93 {
94  static bool first_run = true;
95  static ros::WallTime last_now = ros::WallTime::now();
96 
97  // Grab a snapshot of the current state.
98  std::unordered_map<std::string, ClosedInfo> new_closed_blocks;
99  std::unordered_map<std::string, OpenInfo> threaded_open_blocks;
101  ros::Time ros_now = ros::Time::now();
102  {
103  SpinLockGuard guard(lock_);
104  new_closed_blocks.swap(closed_blocks_);
105  for (auto &pair : open_blocks_) {
106  threaded_open_blocks[pair.first].t0 = pair.second.t0;
107  pair.second.last_report_time = now;
108  }
109  }
110 
111  // Reset all relative max durations.
112  for (auto &pair : all_closed_blocks_) {
113  pair.second.rel_total_duration = ros::Duration(0);
114  pair.second.rel_max_duration = ros::Duration(0);
115  }
116 
117  // Flag to indicate if a new item was added.
118  bool update_index = false;
119 
120  // Merge the new stats into the absolute stats
121  for (auto const &pair : new_closed_blocks) {
122  const auto &label = pair.first;
123  const auto &new_info = pair.second;
124 
125  auto &all_info = all_closed_blocks_[label];
126 
127  if (all_info.key == 0) {
128  update_index = true;
129  all_info.key = all_closed_blocks_.size();
130  }
131 
132  all_info.abs_call_count += new_info.count;
133  all_info.abs_total_duration += durationFromWall(new_info.total_duration);
134  all_info.rel_total_duration += durationFromWall(new_info.rel_duration);
135  all_info.rel_max_duration = std::max(all_info.rel_max_duration,
136  durationFromWall(new_info.max_duration));
137  }
138 
139  // Combine the open blocks from all threads into a single
140  // map.
141  std::unordered_map<std::string, spm::ProfileData> combined_open_blocks;
142  for (auto const &pair : threaded_open_blocks) {
143  const auto &threaded_label = pair.first;
144  const auto &threaded_info = pair.second;
145 
146  size_t slash_index = threaded_label.find('/');
147  if (slash_index == std::string::npos) {
148  ROS_ERROR("Missing expected slash in label: %s", threaded_label.c_str());
149  continue;
150  }
151 
152  ros::Duration duration = durationFromWall(now - threaded_info.t0);
153 
154  const auto label = threaded_label.substr(slash_index+1);
155  auto &new_info = combined_open_blocks[label];
156 
157  if (new_info.key == 0) {
158  auto &all_info = all_closed_blocks_[label];
159  if (all_info.key == 0) {
160  update_index = true;
161  all_info.key = all_closed_blocks_.size();
162  }
163  new_info.key = all_info.key;
164  }
165 
166  new_info.abs_call_count++;
167  new_info.abs_total_duration += duration;
168  if (first_run) {
169  new_info.rel_total_duration += duration;
170  } else {
171  new_info.rel_total_duration += std::min(
172  durationFromWall(now - last_now), duration);
173  }
174  new_info.rel_max_duration = std::max(new_info.rel_max_duration, duration);
175  }
176 
177  if (update_index) {
178  spm::ProfileIndexArray index;
179  index.header.stamp = timeFromWall(now);
180  index.header.frame_id = ros::this_node::getName();
181  index.data.resize(all_closed_blocks_.size());
182 
183  for (auto const &pair : all_closed_blocks_) {
184  size_t i = pair.second.key - 1;
185  index.data[i].key = pair.second.key;
186  index.data[i].label = pair.first;
187  }
188  profiler_index_pub_.publish(index);
189  }
190 
191  // Generate output message
192  spm::ProfileDataArray msg;
193  msg.header.stamp = timeFromWall(now);
194  msg.header.frame_id = ros::this_node::getName();
195  msg.rostime_stamp = ros_now;
196 
197  msg.data.resize(all_closed_blocks_.size());
198  for (auto &pair : all_closed_blocks_) {
199  auto const &item = pair.second;
200  size_t i = item.key - 1;
201 
202  msg.data[i].key = item.key;
203  msg.data[i].abs_call_count = item.abs_call_count;
204  msg.data[i].abs_total_duration = item.abs_total_duration;
205  msg.data[i].rel_total_duration = item.rel_total_duration;
206  msg.data[i].rel_max_duration = item.rel_max_duration;
207  }
208 
209  for (auto &pair : combined_open_blocks) {
210  auto const &item = pair.second;
211  size_t i = item.key - 1;
212  msg.data[i].abs_call_count += item.abs_call_count;
213  msg.data[i].abs_total_duration += item.abs_total_duration;
214  msg.data[i].rel_total_duration += item.rel_total_duration;
215  msg.data[i].rel_max_duration = std::max(
216  msg.data[i].rel_max_duration,
217  item.rel_max_duration);
218  }
219 
220  profiler_data_pub_.publish(msg);
221  first_run = false;
222  last_now = now;
223 }
224 } // namespace swri_profiler
msg
static ros::Publisher profiler_data_pub_
Definition: profiler.cpp:26
void publish(const boost::shared_ptr< M > &message) const
string buffer
static void initializeTLS()
Definition: profiler.cpp:60
static ros::Time timeFromWall(const ros::WallTime &src)
Definition: profiler.cpp:40
static std::unordered_map< std::string, OpenInfo > open_blocks_
Definition: profiler.h:78
static ros::Publisher profiler_index_pub_
Definition: profiler.cpp:25
static ros::Duration durationFromWall(const ros::WallDuration &src)
Definition: profiler.cpp:35
ROSCPP_DECL const std::string & getName()
static void profilerMain()
Definition: profiler.cpp:78
static boost::thread_specific_ptr< TLS > tls_
Definition: profiler.h:87
static void initializeProfiler()
Definition: profiler.cpp:45
static boost::thread profiler_thread_
Definition: profiler.cpp:27
#define ROS_INFO(...)
static SpinLock lock_
Definition: profiler.h:90
static bool profiler_initialized_
Definition: profiler.cpp:24
static std::unordered_map< std::string, spm::ProfileData > all_closed_blocks_
Definition: profiler.cpp:33
ROSCPP_DECL bool ok()
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
static std::unordered_map< std::string, ClosedInfo > closed_blocks_
Definition: profiler.h:83
static WallTime now()
static void collectAndPublish()
Definition: profiler.cpp:92
static Time now()
#define ROS_ERROR(...)
#define ROS_DEBUG(...)


swri_profiler
Author(s):
autogenerated on Fri Nov 27 2020 03:44:17