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