blob: 81988a106a5499b336f2809a86405cfb6635ac4b [file] [log] [blame]
Adedeji Adebisi684ec912021-07-22 18:07:52 +00001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "analyzer.hpp"
kuiyingdfb0cd92023-03-14 11:43:23 +080016
Adedeji Adebisi684ec912021-07-22 18:07:52 +000017#include "histogram.hpp"
18#include "main.hpp"
19#include "sensorhelper.hpp"
20#include "views.hpp"
21#include "xmlparse.hpp"
22
23#include <unistd.h>
kuiyingdfb0cd92023-03-14 11:43:23 +080024
Adedeji Adebisi684ec912021-07-22 18:07:52 +000025#include <atomic>
Sui Chen8c5208f2023-04-21 14:10:05 -070026#include <cassert>
Adedeji Adebisi684ec912021-07-22 18:07:52 +000027#include <filesystem>
28#include <fstream>
29#include <functional>
30#include <iostream>
31#include <sstream>
32#include <string>
33
Sui Chen8c5208f2023-04-21 14:10:05 -070034int AcquireBus(sd_bus** ret);
35
Adedeji Adebisi684ec912021-07-22 18:07:52 +000036extern SensorSnapshot* g_sensor_snapshot;
37extern DBusConnectionSnapshot* g_connection_snapshot;
38extern sd_bus* g_bus;
39extern SensorDetailView* g_sensor_detail_view;
Sui Chen8c5208f2023-04-21 14:10:05 -070040extern FooterView* g_footer_view;
Adedeji Adebisi684ec912021-07-22 18:07:52 +000041
42static std::unordered_map<uint64_t, uint64_t>
43 in_flight_methodcalls; // serial => microseconds
44uint64_t Microseconds()
45{
46 long us; // usec
47 time_t s; // Seconds
48 struct timespec spec;
49 clock_gettime(CLOCK_REALTIME, &spec);
50 s = spec.tv_sec;
51 us = round(spec.tv_nsec / 1000); // Convert nanoseconds to milliseconds
52 if (us > 999999)
53 {
54 s++;
55 us = 0;
56 }
57 return s * 1000000 + us;
58}
59
60int g_update_interval_millises = 2000;
61int GetSummaryIntervalInMillises()
62{
63 return g_update_interval_millises;
64}
65
66bool DBusTopSortFieldIsNumeric(DBusTopSortField field)
67{
68 switch (field)
69 {
70 case kSender:
71 case kDestination:
72 case kInterface:
73 case kPath:
74 case kMember:
75 case kSenderCMD:
76 return false;
77 case kSenderPID:
78 case kMsgPerSec:
79 case kAverageLatency:
80 return true;
81 }
82 return false;
83}
84
85namespace dbus_top_analyzer
86{
kuiyingdfb0cd92023-03-14 11:43:23 +080087DBusTopStatistics g_dbus_statistics;
88Histogram<float> g_mc_time_histogram;
89std::unordered_map<uint32_t, uint64_t> in_flight_methodcalls;
90std::atomic<bool> g_program_done = false;
91std::chrono::time_point<std::chrono::steady_clock> g_last_update;
92DBusTopStatisticsCallback g_callback;
93void SetDBusTopStatisticsCallback(DBusTopStatisticsCallback cb)
94{
95 g_callback = cb;
96}
Adedeji Adebisi684ec912021-07-22 18:07:52 +000097
kuiyingdfb0cd92023-03-14 11:43:23 +080098int UserInputThread()
99{
100 return 0;
101}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000102
kuiyingdfb0cd92023-03-14 11:43:23 +0800103std::string g_dbus_top_conn = " ";
104void SetDBusTopConnectionForMonitoring(const std::string& conn)
105{
106 g_dbus_top_conn = conn;
107}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000108
kuiyingdfb0cd92023-03-14 11:43:23 +0800109// Performs one step of analysis
110void Process()
111{
112 std::chrono::time_point<std::chrono::steady_clock> t =
113 std::chrono::steady_clock::now();
114 std::chrono::time_point<std::chrono::steady_clock> next_update =
115 g_last_update + std::chrono::milliseconds(g_update_interval_millises);
116 if (t >= next_update)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000117 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800118 float seconds_since_last_sample =
119 std::chrono::duration_cast<std::chrono::microseconds>(t -
120 g_last_update)
121 .count() /
122 1000000.0f;
123 g_dbus_statistics.seconds_since_last_sample_ =
124 seconds_since_last_sample;
125 // Update snapshot
126 if (g_callback)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000127 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800128 g_callback(&g_dbus_statistics, &g_mc_time_histogram);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000129 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800130 g_dbus_statistics.Reset();
131 g_last_update = t;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000132 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800133}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000134
kuiyingdfb0cd92023-03-14 11:43:23 +0800135void Finish()
136{
137 g_program_done = true;
138}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000139
kuiyingdfb0cd92023-03-14 11:43:23 +0800140std::vector<std::string> FindAllObjectPathsForService(
Sui Chen8c5208f2023-04-21 14:10:05 -0700141 sd_bus* bus, const std::string& service,
kuiyingdfb0cd92023-03-14 11:43:23 +0800142 std::function<void(const std::string&, const std::vector<std::string>&)>
143 on_interface_cb)
144{
145 sd_bus_error err = SD_BUS_ERROR_NULL;
146 sd_bus_message *m, *reply;
147 std::vector<std::string> paths; // Current iteration
148 std::vector<std::string>
149 all_obj_paths; // All object paths under the supervision of ObjectMapper
150 paths.push_back("/");
151 // busctl call xyz.openbmc_project.ObjectMapper /
152 // org.freedesktop.DBus.Introspectable Introspect
153 while (!paths.empty())
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000154 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800155 // printf("%d paths to explore, total %d paths so far\n",
156 // int(paths.size()), int(all_obj_paths.size()));
157 std::vector<std::string> new_paths;
158 for (const std::string& obj_path : paths)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000159 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800160 all_obj_paths.push_back(obj_path);
161 int r = sd_bus_message_new_method_call(
Sui Chen8c5208f2023-04-21 14:10:05 -0700162 bus, &m, service.c_str(), obj_path.c_str(),
kuiyingdfb0cd92023-03-14 11:43:23 +0800163 "org.freedesktop.DBus.Introspectable", "Introspect");
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000164 if (r < 0)
165 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800166 continue;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000167 }
Sui Chen8c5208f2023-04-21 14:10:05 -0700168 r = sd_bus_call(bus, m, 0, &err, &reply);
kuiyingdfb0cd92023-03-14 11:43:23 +0800169 if (r < 0)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000170 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700171 continue;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000172 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800173 const char* sig = sd_bus_message_get_signature(reply, 0);
174 if (!strcmp(sig, "s"))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000175 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800176 const char* s;
177 int r = sd_bus_message_read(reply, "s", &s);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000178 if (r < 0)
179 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700180 continue;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000181 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800182 else
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000183 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700184 XMLNode* t = ParseXML(std::string(s));
kuiyingdfb0cd92023-03-14 11:43:23 +0800185 std::vector<std::string> ch = t->GetChildNodeNames();
186 if (on_interface_cb != nullptr)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000187 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800188 on_interface_cb(obj_path, t->GetInterfaceNames());
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000189 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800190 DeleteTree(t);
191 for (const std::string& cn : ch)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000192 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800193 std::string ch_path = obj_path;
194 if (obj_path.back() == '/')
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000195 {}
196 else
kuiyingdfb0cd92023-03-14 11:43:23 +0800197 ch_path.push_back('/');
198 ch_path += cn;
199 new_paths.push_back(ch_path);
200 }
201 }
202 }
203 }
204 paths = new_paths;
205 }
206 return all_obj_paths;
207}
208
Sui Chen8c5208f2023-04-21 14:10:05 -0700209void ListAllSensors(sd_bus* bus, DBusConnectionSnapshot** cxn_snapshot,
210 SensorSnapshot** sensor_snapshot)
kuiyingdfb0cd92023-03-14 11:43:23 +0800211{
Sui Chen8c5208f2023-04-21 14:10:05 -0700212 // Craete new snapshots
213 (*cxn_snapshot) = new DBusConnectionSnapshot();
214 (*sensor_snapshot) = new SensorSnapshot(*cxn_snapshot);
215
216 g_footer_view->SetStatusString("1. Listing DBus Names");
217 DBusTopUpdateFooterView();
kuiyingdfb0cd92023-03-14 11:43:23 +0800218 char** names;
Sui Chen8c5208f2023-04-21 14:10:05 -0700219 int r = sd_bus_list_names(bus, &names, nullptr);
kuiyingdfb0cd92023-03-14 11:43:23 +0800220 std::vector<std::string> services;
221 std::vector<int> pids;
222 std::vector<std::string> comms;
223 for (char** ptr = names; ptr && *ptr; ++ptr)
224 {
225 services.push_back(*ptr);
226 free(*ptr);
227 }
228 free(names);
Sui Chen8c5208f2023-04-21 14:10:05 -0700229
230 g_footer_view->SetStatusString("2. Getting Creds");
231 DBusTopUpdateFooterView();
232 size_t N = services.size();
233 for (size_t i = 0; i < N; i++)
kuiyingdfb0cd92023-03-14 11:43:23 +0800234 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700235 if (i == N - 1 || (i % 100) == 99)
236 {
237 g_footer_view->SetStatusString("2. Getting Creds " +
238 std::to_string(i + 1) + "/" +
239 std::to_string(N));
240 DBusTopUpdateFooterView();
241 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800242 const std::string& service = services[i];
243 sd_bus_creds* creds = nullptr;
Sui Chen8c5208f2023-04-21 14:10:05 -0700244 r = sd_bus_get_name_creds(bus, services[i].c_str(),
kuiyingdfb0cd92023-03-14 11:43:23 +0800245 SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_EUID |
246 SD_BUS_CREDS_PID | SD_BUS_CREDS_COMM |
247 SD_BUS_CREDS_UNIQUE_NAME |
248 SD_BUS_CREDS_UNIT | SD_BUS_CREDS_SESSION |
249 SD_BUS_CREDS_DESCRIPTION,
250 &creds);
251 // PID
252 int pid = INVALID;
253 if (r < 0)
Sui Chen8c5208f2023-04-21 14:10:05 -0700254 {}
kuiyingdfb0cd92023-03-14 11:43:23 +0800255 else
256 {
257 r = sd_bus_creds_get_pid(creds, &pid);
258 }
259 pids.push_back(pid);
260 // comm
261 std::string comm;
262 if (pid != INVALID)
263 {
264 std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
265 std::string line;
266 std::getline(ifs, line);
267 for (char c : line)
268 {
269 if (c < 32 || c >= 127)
270 c = ' ';
271 comm.push_back(c);
272 }
273 }
274 comms.push_back(comm);
275 // unique name, also known as "Connection"
276 std::string connection;
277 const char* u;
278 r = sd_bus_creds_get_unique_name(creds, &u);
279 if (r >= 0)
280 {
281 connection = u;
282 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800283 std::string unit;
284 r = sd_bus_creds_get_unit(creds, &u);
285 if (r >= 0)
286 {
287 unit = u;
288 }
Sui Chen8c5208f2023-04-21 14:10:05 -0700289 (*cxn_snapshot)->AddConnection(service, connection, comm, unit, pid);
kuiyingdfb0cd92023-03-14 11:43:23 +0800290 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800291 // busctl call xyz.openbmc_project.ObjectMapper /
292 // org.freedesktop.DBus.Introspectable Introspect
Sui Chen8c5208f2023-04-21 14:10:05 -0700293
294 g_footer_view->SetStatusString("3. Examine objects in ObjectMapper");
kuiyingdfb0cd92023-03-14 11:43:23 +0800295 std::vector<std::string> all_obj_paths = FindAllObjectPathsForService(
Sui Chen8c5208f2023-04-21 14:10:05 -0700296 bus, "xyz.openbmc_project.ObjectMapper", nullptr);
297 N = all_obj_paths.size();
kuiyingdfb0cd92023-03-14 11:43:23 +0800298 sd_bus_error err = SD_BUS_ERROR_NULL;
299 sd_bus_message *m, *reply;
Sui Chen8c5208f2023-04-21 14:10:05 -0700300 for (size_t i = 0; i < N; i++)
kuiyingdfb0cd92023-03-14 11:43:23 +0800301 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700302 if (i % 100 == 99 || i == N - 1)
303 {
304 g_footer_view->SetStatusString(
305 "3. Examine objects in ObjectMapper " + std::to_string(i + 1) +
306 "/" + std::to_string(N));
307 DBusTopUpdateFooterView();
308 }
309
310 const std::string& p = all_obj_paths[i];
kuiyingdfb0cd92023-03-14 11:43:23 +0800311 if (IsSensorObjectPath(p))
312 {
313 err = SD_BUS_ERROR_NULL;
314 r = sd_bus_message_new_method_call(
Sui Chen8c5208f2023-04-21 14:10:05 -0700315 bus, &m, "xyz.openbmc_project.ObjectMapper",
kuiyingdfb0cd92023-03-14 11:43:23 +0800316 "/xyz/openbmc_project/object_mapper",
317 "xyz.openbmc_project.ObjectMapper", "GetObject");
318 if (r < 0)
319 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800320 continue;
321 }
322 r = sd_bus_message_append_basic(m, 's', p.c_str());
323 if (r < 0)
324 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800325 continue;
326 }
327 // empty array
328 r = sd_bus_message_open_container(m, 'a', "s");
329 if (r < 0)
330 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800331 continue;
332 }
333 r = sd_bus_message_close_container(m);
334 if (r < 0)
335 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800336 continue;
337 }
Sui Chen8c5208f2023-04-21 14:10:05 -0700338 r = sd_bus_call(bus, m, 0, &err, &reply);
kuiyingdfb0cd92023-03-14 11:43:23 +0800339 if (r < 0)
Sui Chen8c5208f2023-04-21 14:10:05 -0700340 {}
kuiyingdfb0cd92023-03-14 11:43:23 +0800341 const char* sig = sd_bus_message_get_signature(reply, 0);
342 if (!strcmp(sig, "a{sas}"))
343 {
344 r = sd_bus_message_enter_container(reply, 'a', "{sas}");
345 if (r < 0)
346 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800347 continue;
348 }
349 while (true)
350 {
351 r = sd_bus_message_enter_container(
352 reply, SD_BUS_TYPE_DICT_ENTRY, "sas");
353 if (r < 0)
354 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800355 goto DONE;
356 }
357 else if (r == 0)
358 {}
359 else
360 {
361 // The following 2 correspond to `interface_map` in
362 // phosphor-mapper
363 const char* interface_map_first;
364 r = sd_bus_message_read_basic(reply, 's',
365 &interface_map_first);
366 if (r < 0)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000367 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800368 goto DONE;
369 }
370 r = sd_bus_message_enter_container(reply, 'a', "s");
371 if (r < 0)
372 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800373 goto DONE;
374 }
375 bool has_value_interface = false;
376 while (true)
377 {
378 const char* interface_map_second;
379 r = sd_bus_message_read_basic(
380 reply, 's', &interface_map_second);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000381 if (r < 0)
Sui Chen8c5208f2023-04-21 14:10:05 -0700382 {}
kuiyingdfb0cd92023-03-14 11:43:23 +0800383 else if (r == 0)
384 break;
385 else
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000386 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800387 if (!strcmp(interface_map_second,
388 "xyz.openbmc_project.Sensor.Value"))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000389 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800390 has_value_interface = true;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000391 }
392 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800393 }
394 if (has_value_interface)
395 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700396 (*sensor_snapshot)
397 ->SetSensorVisibleFromObjectMapper(
398 std::string(interface_map_first), p);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000399 }
400 r = sd_bus_message_exit_container(reply);
401 }
402 r = sd_bus_message_exit_container(reply);
403 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800404 r = sd_bus_message_exit_container(reply);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000405 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800406 DONE:
407 {}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000408 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800409 }
Sui Chen8c5208f2023-04-21 14:10:05 -0700410
411 g_footer_view->SetStatusString("4. List Associations in ObjectMapper");
412 DBusTopUpdateFooterView();
413 err = SD_BUS_ERROR_NULL;
414 r = sd_bus_message_new_method_call(
415 bus, &m, "xyz.openbmc_project.ObjectMapper",
416 "/xyz/openbmc_project/object_mapper",
417 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
418 if (r < 0)
kuiyingdfb0cd92023-03-14 11:43:23 +0800419 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700420 assert(0);
421 }
422 r = sd_bus_message_append_basic(m, 's', "/");
423 if (r < 0)
424 {
425 assert(0);
426 }
427 const int zero = 0;
428 r = sd_bus_message_append_basic(m, 'i', &zero);
429 if (r < 0)
430 {
431 assert(0);
432 }
433 r = sd_bus_message_open_container(m, 'a', "s");
434 if (r < 0)
435 {
436 assert(0);
437 }
438 r = sd_bus_message_append_basic(m, 's', "xyz.openbmc_project.Association");
439 if (r < 0)
440 {
441 assert(0);
442 }
443 r = sd_bus_message_close_container(m);
444 if (r < 0)
445 {
446 assert(0);
447 }
448 r = sd_bus_call(bus, m, 0, &err, &reply);
449 if (r < 0)
450 {
451 assert(0);
452 }
453 const char* sig = sd_bus_message_get_signature(reply, 0);
454 if (strcmp(sig, "as"))
455 {
456 assert(0);
457 }
458 r = sd_bus_message_enter_container(reply, 'a', "s");
459 if (r < 0)
460 {
461 assert(0);
462 }
463 std::set<std::string> assoc_paths;
464 while (true)
465 {
466 const char* p;
467 r = sd_bus_message_read_basic(reply, 's', &p);
468 if (r <= 0)
469 break;
470 else
471 {
472 assoc_paths.insert(p);
473 }
474 }
475 r = sd_bus_message_exit_container(reply);
476 if (r < 0)
477 {
478 assert(0);
479 }
480
481 size_t idx = 0;
482 for (const std::string& assoc_path : assoc_paths)
483 {
484 if (idx % 100 == 99 || idx == N - 1)
485 {
486 g_footer_view->SetStatusString(
487 "4. List Associations in ObjectMapper " +
488 std::to_string(idx + 1) + "/" + std::to_string(N));
489 DBusTopUpdateFooterView();
490 }
491 ++idx;
492 err = SD_BUS_ERROR_NULL;
493 r = sd_bus_message_new_method_call(
494 bus, &m, "xyz.openbmc_project.ObjectMapper", assoc_path.c_str(),
495 "org.freedesktop.DBus.Properties", "Get");
496 r = sd_bus_message_append_basic(m, 's',
497 "xyz.openbmc_project.Association");
498 if (r < 0)
499 {
500 assert(0);
501 }
502 r = sd_bus_message_append_basic(m, 's', "endpoints");
503 if (r < 0)
504 {
505 assert(0);
506 }
507 r = sd_bus_call(bus, m, 0, &err, &reply);
508 if (r < 0)
509 {
510 // The object may not have any endpoints
511 continue;
512 }
513 const char* sig = sd_bus_message_get_signature(reply, 0);
514 if (strcmp(sig, "v"))
515 {
516 assert(0);
517 }
518 r = sd_bus_message_enter_container(reply, 'v', "as");
519 if (r < 0)
520 {
521 assert(0);
522 }
523 r = sd_bus_message_enter_container(reply, 'a', "s");
524 if (r < 0)
525 {
526 assert(0);
527 }
528 std::set<std::string> entries;
529 while (true)
530 {
531 const char* p;
532 r = sd_bus_message_read_basic(reply, 's', &p);
533 if (r <= 0)
534 break;
535 entries.insert(p);
536 }
537 r = sd_bus_message_exit_container(reply);
538 if (r < 0)
539 {
540 assert(0);
541 }
542 r = sd_bus_message_exit_container(reply);
543 if (r < 0)
544 {
545 assert(0);
546 }
547
548 (*sensor_snapshot)->AddAssociationEndpoints(assoc_path, entries);
549 }
550
551 g_footer_view->SetStatusString("5. Find Association Definitions");
552 DBusTopUpdateFooterView();
553
554 err = SD_BUS_ERROR_NULL;
555 r = sd_bus_message_new_method_call(
556 bus, &m, "xyz.openbmc_project.ObjectMapper",
557 "/xyz/openbmc_project/object_mapper",
558 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
559 std::vector<std::pair<std::string, std::string>>
560 services_and_objects; // Record the Associations from those pairs
561 r = sd_bus_message_append_basic(m, 's', "/");
562 if (r < 0)
563 {
564 assert(0);
565 }
566 r = sd_bus_message_append_basic(m, 'i', &zero);
567 if (r < 0)
568 {
569 assert(0);
570 }
571 r = sd_bus_message_open_container(m, 'a', "s");
572 if (r < 0)
573 {
574 assert(0);
575 }
576 r = sd_bus_message_append_basic(
577 m, 's', "xyz.openbmc_project.Association.Definitions");
578 if (r < 0)
579 {
580 assert(0);
581 }
582 r = sd_bus_message_close_container(m);
583 if (r < 0)
584 {
585 assert(0);
586 }
587 r = sd_bus_call(bus, m, 0, &err, &reply);
588 if (r < 0)
589 {
590 assert(0);
591 }
592 sig = sd_bus_message_get_signature(reply, 0);
593 if (strcmp(sig, "a{sa{sas}}"))
594 {
595 assert(0);
596 }
597 r = sd_bus_message_enter_container(reply, 'a', "{sa{sas}}");
598 if (r <= 0)
599 {
600 assert(0);
601 }
602
603 idx = 0;
604 N = services_and_objects.size();
605 while (true)
606 {
607 if (idx % 100 == 99 || idx == N - 1)
608 {
609 g_footer_view->SetStatusString("5. Find Association Definitions " +
610 std::to_string(idx + 1) + "/" +
611 std::to_string(N));
612 DBusTopUpdateFooterView();
613 }
614 r = sd_bus_message_enter_container(reply, 'e', "sa{sas}");
615 if (r <= 0)
616 {
617 break;
618 } // e denotes 'dict entry'
619 const char* p; // path
620 r = sd_bus_message_read_basic(reply, 's', &p);
621 if (r <= 0)
622 break;
623 r = sd_bus_message_enter_container(reply, 'a', "{sas}");
624 if (r <= 0)
625 {
626 assert(0);
627 }
628 while (true)
629 {
630 const char* service; // service
631 r = sd_bus_message_enter_container(reply, 'e', "sas");
632 if (r <= 0)
633 {
634 break;
635 }
636 r = sd_bus_message_read_basic(reply, 's', &service);
637 if (r < 0)
638 {
639 assert(0);
640 }
641 services_and_objects.emplace_back(std::string(service),
642 std::string(p));
643 r = sd_bus_message_enter_container(reply, 'a', "s");
644 if (r <= 0)
645 {
646 assert(0);
647 }
648 while (true)
649 {
650 const char* iface;
651 r = sd_bus_message_read_basic(reply, 's', &iface);
652 if (r <= 0)
653 {
654 break;
655 }
656 }
657 r = sd_bus_message_exit_container(reply);
658 if (r < 0)
659 {
660 assert(0);
661 } // exit a
662 r = sd_bus_message_exit_container(reply);
663 if (r < 0)
664 {
665 assert(0);
666 } // exit e
667 }
668 r = sd_bus_message_exit_container(reply);
669 if (r < 0)
670 {
671 assert(0);
672 } // exit a
673 r = sd_bus_message_exit_container(reply);
674 if (r < 0)
675 {
676 assert(0);
677 } // exit e
678 }
679 r = sd_bus_message_exit_container(reply);
680 if (r < 0)
681 {
682 assert(0);
683 } // exit a
684
685 idx = 0;
686 N = services_and_objects.size();
687 for (const std::pair<std::string, std::string>& serv_and_obj :
688 services_and_objects)
689 {
690 if (idx % 100 == 99 || idx == N - 1)
691 {
692 g_footer_view->SetStatusString(
693 "6. Find Associations of Endpoints " + std::to_string(idx + 1) +
694 "/" + std::to_string(N));
695 DBusTopUpdateFooterView();
696 }
697 ++idx;
698 err = SD_BUS_ERROR_NULL;
699 r = sd_bus_message_new_method_call(
700 bus, &m, serv_and_obj.first.c_str(), serv_and_obj.second.c_str(),
701 "org.freedesktop.DBus.Properties", "Get");
702 if (r < 0)
703 {
704 assert(0);
705 }
706 r = sd_bus_message_append_basic(
707 m, 's', "xyz.openbmc_project.Association.Definitions");
708 if (r < 0)
709 {
710 assert(0);
711 }
712 r = sd_bus_message_append_basic(m, 's', "Associations");
713 if (r < 0)
714 {
715 assert(0);
716 }
717 r = sd_bus_call(bus, m, 0, &err, &reply);
718 if (r <= 0)
719 {
720 continue;
721 }
722 sig = sd_bus_message_get_signature(reply, 0);
723 if (strcmp(sig, "v"))
724 {
725 assert(0);
726 }
727 r = sd_bus_message_enter_container(reply, 'v', "a(sss)");
728 if (r <= 0)
729 {
730 continue;
731 }
732 r = sd_bus_message_enter_container(reply, 'a', "(sss)");
733 if (r <= 0)
734 {
735 continue;
736 }
737 while (true)
738 {
739 r = sd_bus_message_enter_container(reply, 'r', "sss");
740 if (r <= 0)
741 {
742 break;
743 } // struct
744 const char *forward, *reverse, *endpoint;
745 r = sd_bus_message_read_basic(reply, 's', &forward);
746 if (r < 0)
747 {
748 break;
749 }
750 r = sd_bus_message_read_basic(reply, 's', &reverse);
751 if (r < 0)
752 {
753 assert(0);
754 }
755 r = sd_bus_message_read_basic(reply, 's', &endpoint);
756 if (r < 0)
757 {
758 assert(0);
759 }
760 (*sensor_snapshot)
761 ->AddAssociationDefinition(
762 serv_and_obj.second, std::string(forward),
763 std::string(reverse), std::string(endpoint));
764 r = sd_bus_message_exit_container(reply);
765 if (r < 0)
766 {
767 assert(0);
768 } // exit struct
769 }
770 r = sd_bus_message_exit_container(reply);
771 if (r < 0)
772 {
773 assert(0);
774 } // exit a
775 r = sd_bus_message_exit_container(reply);
776 if (r < 0)
777 {
778 assert(0);
779 } // exit v
780 }
781
782 g_footer_view->SetStatusString("7. Check HWMon DBus objects");
783 DBusTopUpdateFooterView();
784 for (size_t i = 0; i < comms.size(); i++)
785 {
786 if (i % 100 == 99 || i == N - 1)
787 {
788 g_footer_view->SetStatusString("7. Check HWMon DBus objects " +
789 std::to_string(i + 1) + "/" +
790 std::to_string(N));
791 DBusTopUpdateFooterView();
792 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800793 const std::string& comm = comms[i];
794 const std::string& service = services[i];
795 if (comm.find("phosphor-hwmon-readd") != std::string::npos &&
796 !IsUniqueName(service))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000797 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800798 // printf("Should introspect %s\n", service.c_str());
799 std::vector<std::string> objpaths =
Sui Chen8c5208f2023-04-21 14:10:05 -0700800 FindAllObjectPathsForService(bus, service, nullptr);
kuiyingdfb0cd92023-03-14 11:43:23 +0800801 for (const std::string& op : objpaths)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000802 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800803 if (IsSensorObjectPath(op))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000804 {
Sui Chen8c5208f2023-04-21 14:10:05 -0700805 (*sensor_snapshot)->SetSensorVisibleFromHwmon(service, op);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000806 }
807 }
808 }
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000809 }
Sui Chen8c5208f2023-04-21 14:10:05 -0700810
811 g_footer_view->SetStatusString("DBus object scan complete");
812 DBusTopUpdateFooterView();
kuiyingdfb0cd92023-03-14 11:43:23 +0800813}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000814} // namespace dbus_top_analyzer
815
816void DBusTopStatistics::OnNewDBusMessage(const char* sender,
817 const char* destination,
818 const char* interface,
819 const char* path, const char* member,
820 const char type, sd_bus_message* m)
821{
822 num_messages_++;
823 std::vector<std::string> keys;
824
825 std::string sender_orig = CheckAndFixNullString(sender);
826 std::string dest_orig = CheckAndFixNullString(destination);
827 // For method return messages, we actually want to show the sender
828 // and destination of the original method call, so we swap the
829 // sender and destination
830 if (type == 2)
831 { // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
832 std::swap(sender_orig, dest_orig);
833 }
834
835 // Special case: when PID == 1 (init), the DBus unit would be systemd.
836 // It seems it was not possible to obtain the connection name of systemd
837 // so we manually set it here.
838 const int sender_orig_pid =
839 g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(
840 sender_orig);
841
842 if (sender_orig_pid == 1)
843 {
844 sender_orig = "systemd";
845 }
846 const int dest_orig_pid =
847 g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(dest_orig);
848 if (dest_orig_pid == 1)
849 {
850 dest_orig = "systemd";
851 }
852
853 for (DBusTopSortField field : fields_)
854 {
855 switch (field)
856 {
857 case kSender:
858 keys.push_back(sender_orig);
859 break;
860 case kDestination:
861 keys.push_back(dest_orig);
862 break;
863 case kInterface:
864 keys.push_back(CheckAndFixNullString(interface));
865 break;
866 case kPath:
867 keys.push_back(CheckAndFixNullString(path));
868 break;
869 case kMember:
870 keys.push_back(CheckAndFixNullString(member));
871 break;
872 case kSenderPID:
873 {
874 if (sender_orig_pid != INVALID)
875 {
876 keys.push_back(std::to_string(sender_orig_pid));
877 }
878 else
879 {
880 keys.push_back("(unknown)");
881 }
882 break;
883 }
884 case kSenderCMD:
885 {
886 keys.push_back(
887 g_connection_snapshot->GetConnectionCMDFromNameOrUniqueName(
888 sender_orig));
889 break;
890 }
891 case kMsgPerSec:
892 case kAverageLatency:
893 break; // Don't populate "keys" using these 2 fields
894 }
895 }
896 // keys = combination of fields of user's choice
897
898 if (stats_.count(keys) == 0)
899 {
900 stats_[keys] = DBusTopComputedMetrics();
901 }
902 // Need to update msg/s regardless
903 switch (type)
904 {
905 case 1: // DBUS_MESSAGE_TYPE_METHOD_CALL
906 stats_[keys].num_method_calls++;
907 break;
908 case 2: // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
909 stats_[keys].num_method_returns++;
910 break;
911 case 3: // DBUS_MESSAGE_TYPE_ERROR
912 stats_[keys].num_errors++;
913 break;
914 case 4: // DBUS_MESSAGE_TYPE_SIGNAL
915 stats_[keys].num_signals++;
916 break;
917 }
918 // Update global latency histogram
919 // For method call latency
Patrick Williamsc3aa2a82023-05-10 07:51:38 -0500920 if (type == 1) // DBUS_MESSAGE_TYPE_METHOD_CALL
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000921 {
922 uint64_t serial; // serial == cookie
923 sd_bus_message_get_cookie(m, &serial);
924 in_flight_methodcalls[serial] = Microseconds();
925 }
Patrick Williamsc3aa2a82023-05-10 07:51:38 -0500926 else if (type == 2) // DBUS_MESSAGE_TYPE_MEHOTD_RETURN
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000927 {
928 uint64_t reply_serial = 0; // serial == cookie
929 sd_bus_message_get_reply_cookie(m, &reply_serial);
930 if (in_flight_methodcalls.count(reply_serial) > 0)
931 {
Patrick Williamsf5c0b9d2023-03-14 09:31:01 -0500932 float dt_usec = Microseconds() -
933 in_flight_methodcalls[reply_serial];
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000934 in_flight_methodcalls.erase(reply_serial);
935 dbus_top_analyzer::g_mc_time_histogram.AddSample(dt_usec);
936
937 // Add method call count and total latency to the corresponding key
938 stats_[keys].total_latency_usec += dt_usec;
939 }
940 }
941 // For meaning of type see here
942 // https://dbus.freedesktop.org/doc/api/html/group__DBusProtocol.html#ga4a9012edd7f22342f845e98150aeb858
943 switch (type)
944 {
945 case 1:
946 num_mc_++;
947 break;
948 case 2:
949 num_mr_++;
950 break;
951 case 3:
952 num_error_++;
953 break;
954 case 4:
955 num_sig_++;
956 break;
957 }
958}