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