| 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 |