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
3 // found in the LICENSE file.
5 #include "dbus/dbus_statistics.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/stringprintf.h"
13 #include "base/time.h"
19 // Used to store dbus statistics sorted alphabetically by service, interface,
20 // then method (using std::string <).
22 Stat(const std::string
& service
,
23 const std::string
& interface
,
24 const std::string
& method
)
30 sent_blocking_method_calls(0) {
33 std::string interface
;
35 int sent_method_calls
;
37 int sent_blocking_method_calls
;
39 bool Compare(const Stat
& other
) const {
40 if (service
!= other
.service
)
41 return service
< other
.service
;
42 if (interface
!= other
.interface
)
43 return interface
< other
.interface
;
44 return method
< other
.method
;
48 bool operator()(Stat
* lhs
, Stat
* rhs
) const {
50 return lhs
->Compare(*rhs
);
55 typedef std::set
<Stat
*, Stat::PtrCompare
> StatSet
;
57 //------------------------------------------------------------------------------
60 // Simple class for gathering DBus usage statistics.
61 class DBusStatistics
{
63 DBusStatistics() : start_time_(base::Time::Now()) {
67 STLDeleteContainerPointers(stats_
.begin(), stats_
.end());
70 // Enum to specify which field in Stat to increment in AddStat
72 TYPE_SENT_METHOD_CALLS
,
73 TYPE_RECEIVED_SIGNALS
,
74 TYPE_SENT_BLOCKING_METHOD_CALLS
77 // Add a call to |method| for |interface|. See also MethodCall in message.h.
78 void AddStat(const std::string
& service
,
79 const std::string
& interface
,
80 const std::string
& method
,
82 Stat
* stat
= GetStat(service
, interface
, method
, true);
84 if (type
== TYPE_SENT_METHOD_CALLS
)
85 ++stat
->sent_method_calls
;
86 else if (type
== TYPE_RECEIVED_SIGNALS
)
87 ++stat
->received_signals
;
88 else if (type
== TYPE_SENT_BLOCKING_METHOD_CALLS
)
89 ++stat
->sent_blocking_method_calls
;
94 // Look up the Stat entry in |stats_|. If |add_stat| is true, add a new entry
95 // if one does not already exist.
96 Stat
* GetStat(const std::string
& service
,
97 const std::string
& interface
,
98 const std::string
& method
,
100 scoped_ptr
<Stat
> stat(new Stat(service
, interface
, method
));
101 StatSet::iterator found
= stats_
.find(stat
.get());
102 if (found
!= stats_
.end())
106 found
= stats_
.insert(stat
.release()).first
;
110 StatSet
& stats() { return stats_
; }
111 base::Time
start_time() { return start_time_
; }
115 base::Time start_time_
;
117 DISALLOW_COPY_AND_ASSIGN(DBusStatistics
);
120 DBusStatistics
* g_dbus_statistics
= NULL
;
124 //------------------------------------------------------------------------------
126 namespace statistics
{
129 if (g_dbus_statistics
)
130 delete g_dbus_statistics
; // reset statistics
131 g_dbus_statistics
= new DBusStatistics();
135 delete g_dbus_statistics
;
136 g_dbus_statistics
= NULL
;
139 void AddSentMethodCall(const std::string
& service
,
140 const std::string
& interface
,
141 const std::string
& method
) {
142 if (!g_dbus_statistics
)
144 g_dbus_statistics
->AddStat(
145 service
, interface
, method
, DBusStatistics::TYPE_SENT_METHOD_CALLS
);
148 void AddReceivedSignal(const std::string
& service
,
149 const std::string
& interface
,
150 const std::string
& method
) {
151 if (!g_dbus_statistics
)
153 g_dbus_statistics
->AddStat(
154 service
, interface
, method
, DBusStatistics::TYPE_RECEIVED_SIGNALS
);
157 void AddBlockingSentMethodCall(const std::string
& service
,
158 const std::string
& interface
,
159 const std::string
& method
) {
160 if (!g_dbus_statistics
)
162 g_dbus_statistics
->AddStat(
163 service
, interface
, method
,
164 DBusStatistics::TYPE_SENT_BLOCKING_METHOD_CALLS
);
167 // NOTE: If the output format is changed, be certain to change the test
168 // expectations as well.
169 std::string
GetAsString(ShowInString show
, FormatString format
) {
170 if (!g_dbus_statistics
)
171 return "DBusStatistics not initialized.";
173 const StatSet
& stats
= g_dbus_statistics
->stats();
175 return "No DBus calls.";
177 base::TimeDelta dtime
= base::Time::Now() - g_dbus_statistics
->start_time();
178 int dminutes
= dtime
.InMinutes();
179 dminutes
= std::max(dminutes
, 1);
182 int sent
= 0, received
= 0, sent_blocking
= 0;
183 // Stats are stored in order by service, then interface, then method.
184 for (StatSet::const_iterator iter
= stats
.begin(); iter
!= stats
.end(); ) {
185 StatSet::const_iterator cur_iter
= iter
;
186 StatSet::const_iterator next_iter
= ++iter
;
187 const Stat
* stat
= *cur_iter
;
188 sent
+= stat
->sent_method_calls
;
189 received
+= stat
->received_signals
;
190 sent_blocking
+= stat
->sent_blocking_method_calls
;
191 // If this is not the last stat, and if the next stat matches the current
193 if (next_iter
!= stats
.end() &&
194 (*next_iter
)->service
== stat
->service
&&
195 (show
< SHOW_INTERFACE
|| (*next_iter
)->interface
== stat
->interface
) &&
196 (show
< SHOW_METHOD
|| (*next_iter
)->method
== stat
->method
))
199 if (!sent
&& !received
&& !sent_blocking
)
200 continue; // No stats collected for this line, skip it and continue.
202 // Add a line to the result and clear the counts.
204 if (show
== SHOW_SERVICE
) {
205 line
+= stat
->service
;
207 // The interface usually includes the service so don't show both.
208 line
+= stat
->interface
;
209 if (show
>= SHOW_METHOD
)
210 line
+= "." + stat
->method
;
212 line
+= StringPrintf(":");
214 line
+= StringPrintf(" Sent (BLOCKING):");
215 if (format
== FORMAT_TOTALS
)
216 line
+= StringPrintf(" %d", sent_blocking
);
217 else if (format
== FORMAT_PER_MINUTE
)
218 line
+= StringPrintf(" %d/min", sent_blocking
/ dminutes
);
219 else if (format
== FORMAT_ALL
)
220 line
+= StringPrintf(" %d (%d/min)",
221 sent_blocking
, sent_blocking
/ dminutes
);
224 line
+= StringPrintf(" Sent:");
225 if (format
== FORMAT_TOTALS
)
226 line
+= StringPrintf(" %d", sent
);
227 else if (format
== FORMAT_PER_MINUTE
)
228 line
+= StringPrintf(" %d/min", sent
/ dminutes
);
229 else if (format
== FORMAT_ALL
)
230 line
+= StringPrintf(" %d (%d/min)", sent
, sent
/ dminutes
);
233 line
+= StringPrintf(" Received:");
234 if (format
== FORMAT_TOTALS
)
235 line
+= StringPrintf(" %d", received
);
236 else if (format
== FORMAT_PER_MINUTE
)
237 line
+= StringPrintf(" %d/min", received
/ dminutes
);
238 else if (format
== FORMAT_ALL
)
239 line
+= StringPrintf(" %d (%d/min)", received
, received
/ dminutes
);
241 result
+= line
+ "\n";
251 bool GetCalls(const std::string
& service
,
252 const std::string
& interface
,
253 const std::string
& method
,
257 if (!g_dbus_statistics
)
259 Stat
* stat
= g_dbus_statistics
->GetStat(service
, interface
, method
, false);
262 *sent
= stat
->sent_method_calls
;
263 *received
= stat
->received_signals
;
264 *blocking
= stat
->sent_blocking_method_calls
;
268 } // namespace testing
270 } // namespace statistics