OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "dbus/dbus_statistics.h" | 5 #include "dbus/dbus_statistics.h" |
6 | 6 |
7 #include <memory> | 7 #include <map> |
8 #include <set> | 8 #include <tuple> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/stl_util.h" | |
13 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
14 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
15 #include "base/time/time.h" | 14 #include "base/time/time.h" |
16 | 15 |
17 namespace dbus { | 16 namespace dbus { |
18 | 17 |
19 namespace { | 18 namespace { |
20 | 19 |
21 // Used to store dbus statistics sorted alphabetically by service, interface, | 20 struct StatKey { |
22 // then method (using std::string <). | |
23 struct Stat { | |
24 Stat(const std::string& service, | |
25 const std::string& interface, | |
26 const std::string& method) | |
27 : service(service), | |
28 interface(interface), | |
29 method(method), | |
30 sent_method_calls(0), | |
31 received_signals(0), | |
32 sent_blocking_method_calls(0) { | |
33 } | |
34 std::string service; | 21 std::string service; |
35 std::string interface; | 22 std::string interface; |
36 std::string method; | 23 std::string method; |
37 int sent_method_calls; | |
38 int received_signals; | |
39 int sent_blocking_method_calls; | |
40 | |
41 bool Compare(const Stat& other) const { | |
42 if (service != other.service) | |
43 return service < other.service; | |
44 if (interface != other.interface) | |
45 return interface < other.interface; | |
46 return method < other.method; | |
47 } | |
48 | |
49 struct PtrCompare { | |
50 bool operator()(Stat* lhs, Stat* rhs) const { | |
51 DCHECK(lhs && rhs); | |
52 return lhs->Compare(*rhs); | |
53 } | |
54 }; | |
55 }; | 24 }; |
56 | 25 |
57 typedef std::set<Stat*, Stat::PtrCompare> StatSet; | 26 bool operator<(const StatKey& lhs, const StatKey& rhs) { |
| 27 return std::tie(lhs.service, lhs.interface, lhs.method) < |
| 28 std::tie(rhs.service, rhs.interface, rhs.method); |
| 29 } |
| 30 |
| 31 struct StatValue { |
| 32 int sent_method_calls = 0; |
| 33 int received_signals = 0; |
| 34 int sent_blocking_method_calls = 0; |
| 35 }; |
| 36 |
| 37 using StatMap = std::map<StatKey, StatValue>; |
58 | 38 |
59 //------------------------------------------------------------------------------ | 39 //------------------------------------------------------------------------------ |
60 // DBusStatistics | 40 // DBusStatistics |
61 | 41 |
62 // Simple class for gathering DBus usage statistics. | 42 // Simple class for gathering DBus usage statistics. |
63 class DBusStatistics { | 43 class DBusStatistics { |
64 public: | 44 public: |
65 DBusStatistics() | 45 DBusStatistics() |
66 : start_time_(base::Time::Now()), | 46 : start_time_(base::Time::Now()), |
67 origin_thread_id_(base::PlatformThread::CurrentId()) { | 47 origin_thread_id_(base::PlatformThread::CurrentId()) { |
68 } | 48 } |
69 | 49 |
70 ~DBusStatistics() { | 50 ~DBusStatistics() { |
71 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); | 51 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); |
72 base::STLDeleteContainerPointers(stats_.begin(), stats_.end()); | |
73 } | 52 } |
74 | 53 |
75 // Enum to specify which field in Stat to increment in AddStat | 54 // Enum to specify which field in Stat to increment in AddStat. |
76 enum StatType { | 55 enum StatType { |
77 TYPE_SENT_METHOD_CALLS, | 56 TYPE_SENT_METHOD_CALLS, |
78 TYPE_RECEIVED_SIGNALS, | 57 TYPE_RECEIVED_SIGNALS, |
79 TYPE_SENT_BLOCKING_METHOD_CALLS | 58 TYPE_SENT_BLOCKING_METHOD_CALLS |
80 }; | 59 }; |
81 | 60 |
82 // Add a call to |method| for |interface|. See also MethodCall in message.h. | 61 // Add a call to |method| for |interface|. See also MethodCall in message.h. |
83 void AddStat(const std::string& service, | 62 void AddStat(const std::string& service, |
84 const std::string& interface, | 63 const std::string& interface, |
85 const std::string& method, | 64 const std::string& method, |
86 StatType type) { | 65 StatType type) { |
87 if (base::PlatformThread::CurrentId() != origin_thread_id_) { | 66 if (base::PlatformThread::CurrentId() != origin_thread_id_) { |
88 DVLOG(1) << "Ignoring DBusStatistics::AddStat call from thread: " | 67 DVLOG(1) << "Ignoring DBusStatistics::AddStat call from thread: " |
89 << base::PlatformThread::CurrentId(); | 68 << base::PlatformThread::CurrentId(); |
90 return; | 69 return; |
91 } | 70 } |
92 Stat* stat = GetStat(service, interface, method, true); | 71 StatValue* stat = GetStats(service, interface, method, true); |
93 DCHECK(stat); | 72 DCHECK(stat); |
94 if (type == TYPE_SENT_METHOD_CALLS) | 73 if (type == TYPE_SENT_METHOD_CALLS) |
95 ++stat->sent_method_calls; | 74 ++stat->sent_method_calls; |
96 else if (type == TYPE_RECEIVED_SIGNALS) | 75 else if (type == TYPE_RECEIVED_SIGNALS) |
97 ++stat->received_signals; | 76 ++stat->received_signals; |
98 else if (type == TYPE_SENT_BLOCKING_METHOD_CALLS) | 77 else if (type == TYPE_SENT_BLOCKING_METHOD_CALLS) |
99 ++stat->sent_blocking_method_calls; | 78 ++stat->sent_blocking_method_calls; |
100 else | 79 else |
101 NOTREACHED(); | 80 NOTREACHED(); |
102 } | 81 } |
103 | 82 |
104 // Look up the Stat entry in |stats_|. If |add_stat| is true, add a new entry | 83 // Look up the Stat entry in |stats_|. If |add_stat| is true, add a new entry |
105 // if one does not already exist. | 84 // if one does not already exist. |
106 Stat* GetStat(const std::string& service, | 85 StatValue* GetStats(const std::string& service, |
107 const std::string& interface, | 86 const std::string& interface, |
108 const std::string& method, | 87 const std::string& method, |
109 bool add_stat) { | 88 bool add_stat) { |
110 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); | 89 DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId()); |
111 std::unique_ptr<Stat> stat(new Stat(service, interface, method)); | 90 |
112 StatSet::iterator found = stats_.find(stat.get()); | 91 StatKey key = {service, interface, method}; |
113 if (found != stats_.end()) | 92 auto it = stats_.find(key); |
114 return *found; | 93 if (it != stats_.end()) |
| 94 return &(it->second); |
| 95 |
115 if (!add_stat) | 96 if (!add_stat) |
116 return NULL; | 97 return nullptr; |
117 found = stats_.insert(stat.release()).first; | 98 |
118 return *found; | 99 return &(stats_[key]); |
119 } | 100 } |
120 | 101 |
121 StatSet& stats() { return stats_; } | 102 StatMap& stats() { return stats_; } |
122 base::Time start_time() { return start_time_; } | 103 base::Time start_time() { return start_time_; } |
123 | 104 |
124 private: | 105 private: |
125 StatSet stats_; | 106 StatMap stats_; |
126 base::Time start_time_; | 107 base::Time start_time_; |
127 base::PlatformThreadId origin_thread_id_; | 108 base::PlatformThreadId origin_thread_id_; |
128 | 109 |
129 DISALLOW_COPY_AND_ASSIGN(DBusStatistics); | 110 DISALLOW_COPY_AND_ASSIGN(DBusStatistics); |
130 }; | 111 }; |
131 | 112 |
132 DBusStatistics* g_dbus_statistics = NULL; | 113 DBusStatistics* g_dbus_statistics = nullptr; |
133 | 114 |
134 } // namespace | 115 } // namespace |
135 | 116 |
136 //------------------------------------------------------------------------------ | 117 //------------------------------------------------------------------------------ |
137 | 118 |
138 namespace statistics { | 119 namespace statistics { |
139 | 120 |
140 void Initialize() { | 121 void Initialize() { |
141 if (g_dbus_statistics) | 122 if (g_dbus_statistics) |
142 delete g_dbus_statistics; // reset statistics | 123 delete g_dbus_statistics; // reset statistics |
143 g_dbus_statistics = new DBusStatistics(); | 124 g_dbus_statistics = new DBusStatistics(); |
144 } | 125 } |
145 | 126 |
146 void Shutdown() { | 127 void Shutdown() { |
147 delete g_dbus_statistics; | 128 delete g_dbus_statistics; |
148 g_dbus_statistics = NULL; | 129 g_dbus_statistics = nullptr; |
149 } | 130 } |
150 | 131 |
151 void AddSentMethodCall(const std::string& service, | 132 void AddSentMethodCall(const std::string& service, |
152 const std::string& interface, | 133 const std::string& interface, |
153 const std::string& method) { | 134 const std::string& method) { |
154 if (!g_dbus_statistics) | 135 if (!g_dbus_statistics) |
155 return; | 136 return; |
156 g_dbus_statistics->AddStat( | 137 g_dbus_statistics->AddStat( |
157 service, interface, method, DBusStatistics::TYPE_SENT_METHOD_CALLS); | 138 service, interface, method, DBusStatistics::TYPE_SENT_METHOD_CALLS); |
158 } | 139 } |
(...skipping 16 matching lines...) Expand all Loading... |
175 service, interface, method, | 156 service, interface, method, |
176 DBusStatistics::TYPE_SENT_BLOCKING_METHOD_CALLS); | 157 DBusStatistics::TYPE_SENT_BLOCKING_METHOD_CALLS); |
177 } | 158 } |
178 | 159 |
179 // NOTE: If the output format is changed, be certain to change the test | 160 // NOTE: If the output format is changed, be certain to change the test |
180 // expectations as well. | 161 // expectations as well. |
181 std::string GetAsString(ShowInString show, FormatString format) { | 162 std::string GetAsString(ShowInString show, FormatString format) { |
182 if (!g_dbus_statistics) | 163 if (!g_dbus_statistics) |
183 return "DBusStatistics not initialized."; | 164 return "DBusStatistics not initialized."; |
184 | 165 |
185 const StatSet& stats = g_dbus_statistics->stats(); | 166 const StatMap& stats = g_dbus_statistics->stats(); |
186 if (stats.empty()) | 167 if (stats.empty()) |
187 return "No DBus calls."; | 168 return "No DBus calls."; |
188 | 169 |
189 base::TimeDelta dtime = base::Time::Now() - g_dbus_statistics->start_time(); | 170 base::TimeDelta dtime = base::Time::Now() - g_dbus_statistics->start_time(); |
190 int dminutes = dtime.InMinutes(); | 171 int dminutes = dtime.InMinutes(); |
191 dminutes = std::max(dminutes, 1); | 172 dminutes = std::max(dminutes, 1); |
192 | 173 |
193 std::string result; | 174 std::string result; |
194 int sent = 0, received = 0, sent_blocking = 0; | 175 int sent = 0, received = 0, sent_blocking = 0; |
195 // Stats are stored in order by service, then interface, then method. | 176 // Stats are stored in order by service, then interface, then method. |
196 for (StatSet::const_iterator iter = stats.begin(); iter != stats.end(); ) { | 177 for (auto iter = stats.begin(); iter != stats.end();) { |
197 StatSet::const_iterator cur_iter = iter; | 178 auto cur_iter = iter; |
198 StatSet::const_iterator next_iter = ++iter; | 179 auto next_iter = ++iter; |
199 const Stat* stat = *cur_iter; | 180 const StatKey& stat_key = cur_iter->first; |
200 sent += stat->sent_method_calls; | 181 const StatValue& stat = cur_iter->second; |
201 received += stat->received_signals; | 182 sent += stat.sent_method_calls; |
202 sent_blocking += stat->sent_blocking_method_calls; | 183 received += stat.received_signals; |
| 184 sent_blocking += stat.sent_blocking_method_calls; |
203 // If this is not the last stat, and if the next stat matches the current | 185 // If this is not the last stat, and if the next stat matches the current |
204 // stat, continue. | 186 // stat, continue. |
205 if (next_iter != stats.end() && | 187 if (next_iter != stats.end() && |
206 (*next_iter)->service == stat->service && | 188 next_iter->first.service == stat_key.service && |
207 (show < SHOW_INTERFACE || (*next_iter)->interface == stat->interface) && | 189 (show < SHOW_INTERFACE || |
208 (show < SHOW_METHOD || (*next_iter)->method == stat->method)) | 190 next_iter->first.interface == stat_key.interface) && |
| 191 (show < SHOW_METHOD || next_iter->first.method == stat_key.method)) |
209 continue; | 192 continue; |
210 | 193 |
211 if (!sent && !received && !sent_blocking) | 194 if (!sent && !received && !sent_blocking) |
212 continue; // No stats collected for this line, skip it and continue. | 195 continue; // No stats collected for this line, skip it and continue. |
213 | 196 |
214 // Add a line to the result and clear the counts. | 197 // Add a line to the result and clear the counts. |
215 std::string line; | 198 std::string line; |
216 if (show == SHOW_SERVICE) { | 199 if (show == SHOW_SERVICE) { |
217 line += stat->service; | 200 line += stat_key.service; |
218 } else { | 201 } else { |
219 // The interface usually includes the service so don't show both. | 202 // The interface usually includes the service so don't show both. |
220 line += stat->interface; | 203 line += stat_key.interface; |
221 if (show >= SHOW_METHOD) | 204 if (show >= SHOW_METHOD) |
222 line += "." + stat->method; | 205 line += "." + stat_key.method; |
223 } | 206 } |
224 line += base::StringPrintf(":"); | 207 line += base::StringPrintf(":"); |
225 if (sent_blocking) { | 208 if (sent_blocking) { |
226 line += base::StringPrintf(" Sent (BLOCKING):"); | 209 line += base::StringPrintf(" Sent (BLOCKING):"); |
227 if (format == FORMAT_TOTALS) | 210 if (format == FORMAT_TOTALS) |
228 line += base::StringPrintf(" %d", sent_blocking); | 211 line += base::StringPrintf(" %d", sent_blocking); |
229 else if (format == FORMAT_PER_MINUTE) | 212 else if (format == FORMAT_PER_MINUTE) |
230 line += base::StringPrintf(" %d/min", sent_blocking / dminutes); | 213 line += base::StringPrintf(" %d/min", sent_blocking / dminutes); |
231 else if (format == FORMAT_ALL) | 214 else if (format == FORMAT_ALL) |
232 line += base::StringPrintf(" %d (%d/min)", | 215 line += base::StringPrintf(" %d (%d/min)", |
(...skipping 29 matching lines...) Expand all Loading... |
262 namespace testing { | 245 namespace testing { |
263 | 246 |
264 bool GetCalls(const std::string& service, | 247 bool GetCalls(const std::string& service, |
265 const std::string& interface, | 248 const std::string& interface, |
266 const std::string& method, | 249 const std::string& method, |
267 int* sent, | 250 int* sent, |
268 int* received, | 251 int* received, |
269 int* blocking) { | 252 int* blocking) { |
270 if (!g_dbus_statistics) | 253 if (!g_dbus_statistics) |
271 return false; | 254 return false; |
272 Stat* stat = g_dbus_statistics->GetStat(service, interface, method, false); | 255 StatValue* stat = |
| 256 g_dbus_statistics->GetStats(service, interface, method, false); |
273 if (!stat) | 257 if (!stat) |
274 return false; | 258 return false; |
275 *sent = stat->sent_method_calls; | 259 *sent = stat->sent_method_calls; |
276 *received = stat->received_signals; | 260 *received = stat->received_signals; |
277 *blocking = stat->sent_blocking_method_calls; | 261 *blocking = stat->sent_blocking_method_calls; |
278 return true; | 262 return true; |
279 } | 263 } |
280 | 264 |
281 } // namespace testing | 265 } // namespace testing |
282 | 266 |
283 } // namespace statistics | 267 } // namespace statistics |
284 } // namespace dbus | 268 } // namespace dbus |
OLD | NEW |