xref: /aosp_15_r20/external/libchrome/dbus/dbus_statistics.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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