blob: b26a53a9d67d991f58a6ab6f481a6e4483a5244c [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>
26#include <filesystem>
27#include <fstream>
28#include <functional>
29#include <iostream>
30#include <sstream>
31#include <string>
32
33extern SensorSnapshot* g_sensor_snapshot;
34extern DBusConnectionSnapshot* g_connection_snapshot;
35extern sd_bus* g_bus;
36extern SensorDetailView* g_sensor_detail_view;
37
38static std::unordered_map<uint64_t, uint64_t>
39 in_flight_methodcalls; // serial => microseconds
40uint64_t Microseconds()
41{
42 long us; // usec
43 time_t s; // Seconds
44 struct timespec spec;
45 clock_gettime(CLOCK_REALTIME, &spec);
46 s = spec.tv_sec;
47 us = round(spec.tv_nsec / 1000); // Convert nanoseconds to milliseconds
48 if (us > 999999)
49 {
50 s++;
51 us = 0;
52 }
53 return s * 1000000 + us;
54}
55
56int g_update_interval_millises = 2000;
57int GetSummaryIntervalInMillises()
58{
59 return g_update_interval_millises;
60}
61
62bool DBusTopSortFieldIsNumeric(DBusTopSortField field)
63{
64 switch (field)
65 {
66 case kSender:
67 case kDestination:
68 case kInterface:
69 case kPath:
70 case kMember:
71 case kSenderCMD:
72 return false;
73 case kSenderPID:
74 case kMsgPerSec:
75 case kAverageLatency:
76 return true;
77 }
78 return false;
79}
80
81namespace dbus_top_analyzer
82{
kuiyingdfb0cd92023-03-14 11:43:23 +080083DBusTopStatistics g_dbus_statistics;
84Histogram<float> g_mc_time_histogram;
85std::unordered_map<uint32_t, uint64_t> in_flight_methodcalls;
86std::atomic<bool> g_program_done = false;
87std::chrono::time_point<std::chrono::steady_clock> g_last_update;
88DBusTopStatisticsCallback g_callback;
89void SetDBusTopStatisticsCallback(DBusTopStatisticsCallback cb)
90{
91 g_callback = cb;
92}
Adedeji Adebisi684ec912021-07-22 18:07:52 +000093
kuiyingdfb0cd92023-03-14 11:43:23 +080094int UserInputThread()
95{
96 return 0;
97}
Adedeji Adebisi684ec912021-07-22 18:07:52 +000098
kuiyingdfb0cd92023-03-14 11:43:23 +080099std::string g_dbus_top_conn = " ";
100void SetDBusTopConnectionForMonitoring(const std::string& conn)
101{
102 g_dbus_top_conn = conn;
103}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000104
kuiyingdfb0cd92023-03-14 11:43:23 +0800105// Performs one step of analysis
106void Process()
107{
108 std::chrono::time_point<std::chrono::steady_clock> t =
109 std::chrono::steady_clock::now();
110 std::chrono::time_point<std::chrono::steady_clock> next_update =
111 g_last_update + std::chrono::milliseconds(g_update_interval_millises);
112 if (t >= next_update)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000113 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800114 float seconds_since_last_sample =
115 std::chrono::duration_cast<std::chrono::microseconds>(t -
116 g_last_update)
117 .count() /
118 1000000.0f;
119 g_dbus_statistics.seconds_since_last_sample_ =
120 seconds_since_last_sample;
121 // Update snapshot
122 if (g_callback)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000123 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800124 g_callback(&g_dbus_statistics, &g_mc_time_histogram);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000125 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800126 g_dbus_statistics.Reset();
127 g_last_update = t;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000128 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800129}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000130
kuiyingdfb0cd92023-03-14 11:43:23 +0800131void Finish()
132{
133 g_program_done = true;
134}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000135
kuiyingdfb0cd92023-03-14 11:43:23 +0800136std::vector<std::string> FindAllObjectPathsForService(
137 const std::string& service,
138 std::function<void(const std::string&, const std::vector<std::string>&)>
139 on_interface_cb)
140{
141 sd_bus_error err = SD_BUS_ERROR_NULL;
142 sd_bus_message *m, *reply;
143 std::vector<std::string> paths; // Current iteration
144 std::vector<std::string>
145 all_obj_paths; // All object paths under the supervision of ObjectMapper
146 paths.push_back("/");
147 // busctl call xyz.openbmc_project.ObjectMapper /
148 // org.freedesktop.DBus.Introspectable Introspect
149 while (!paths.empty())
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000150 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800151 // printf("%d paths to explore, total %d paths so far\n",
152 // int(paths.size()), int(all_obj_paths.size()));
153 std::vector<std::string> new_paths;
154 for (const std::string& obj_path : paths)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000155 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800156 all_obj_paths.push_back(obj_path);
157 int r = sd_bus_message_new_method_call(
158 g_bus, &m, service.c_str(), obj_path.c_str(),
159 "org.freedesktop.DBus.Introspectable", "Introspect");
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000160 if (r < 0)
161 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800162 printf("Oh! Cannot create new method call. r=%d, strerror=%s\n",
163 r, strerror(-r));
164 continue;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000165 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800166 r = sd_bus_call(g_bus, m, 0, &err, &reply);
167 if (r < 0)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000168 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800169 printf("Could not execute method call, r=%d, strerror=%s\n", r,
170 strerror(-r));
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000171 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800172 const char* sig = sd_bus_message_get_signature(reply, 0);
173 if (!strcmp(sig, "s"))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000174 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800175 const char* s;
176 int r = sd_bus_message_read(reply, "s", &s);
177 std::string s1(s);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000178 if (r < 0)
179 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800180 printf("Could not read string payload, r=%d, strerror=%s\n",
181 r, strerror(-r));
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000182 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800183 else
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000184 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800185 XMLNode* t = ParseXML(s1);
186 std::vector<std::string> ch = t->GetChildNodeNames();
187 if (on_interface_cb != nullptr)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000188 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800189 on_interface_cb(obj_path, t->GetInterfaceNames());
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000190 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800191 DeleteTree(t);
192 for (const std::string& cn : ch)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000193 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800194 std::string ch_path = obj_path;
195 if (obj_path.back() == '/')
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000196 {}
197 else
kuiyingdfb0cd92023-03-14 11:43:23 +0800198 ch_path.push_back('/');
199 ch_path += cn;
200 new_paths.push_back(ch_path);
201 }
202 }
203 }
204 }
205 paths = new_paths;
206 }
207 return all_obj_paths;
208}
209
210void ListAllSensors()
211{
212 g_connection_snapshot = new DBusConnectionSnapshot();
213 printf("1. Getting names\n");
214 char** names;
215 int r = sd_bus_list_names(g_bus, &names, nullptr);
216 std::vector<std::string> services;
217 std::vector<int> pids;
218 std::vector<std::string> comms;
219 for (char** ptr = names; ptr && *ptr; ++ptr)
220 {
221 services.push_back(*ptr);
222 free(*ptr);
223 }
224 free(names);
225 printf("2. Getting creds of each name\n");
226 for (int i = 0; i < static_cast<int>(services.size()); i++)
227 {
228 const std::string& service = services[i];
229 sd_bus_creds* creds = nullptr;
230 r = sd_bus_get_name_creds(g_bus, services[i].c_str(),
231 SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_EUID |
232 SD_BUS_CREDS_PID | SD_BUS_CREDS_COMM |
233 SD_BUS_CREDS_UNIQUE_NAME |
234 SD_BUS_CREDS_UNIT | SD_BUS_CREDS_SESSION |
235 SD_BUS_CREDS_DESCRIPTION,
236 &creds);
237 // PID
238 int pid = INVALID;
239 if (r < 0)
240 {
241 printf("Oh! Cannot get creds for %s\n", services[i].c_str());
242 }
243 else
244 {
245 r = sd_bus_creds_get_pid(creds, &pid);
246 }
247 pids.push_back(pid);
248 // comm
249 std::string comm;
250 if (pid != INVALID)
251 {
252 std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
253 std::string line;
254 std::getline(ifs, line);
255 for (char c : line)
256 {
257 if (c < 32 || c >= 127)
258 c = ' ';
259 comm.push_back(c);
260 }
261 }
262 comms.push_back(comm);
263 // unique name, also known as "Connection"
264 std::string connection;
265 const char* u;
266 r = sd_bus_creds_get_unique_name(creds, &u);
267 if (r >= 0)
268 {
269 connection = u;
270 }
271 else
272 {
273 printf("Oh! Could not get unique name for %s\n", service.c_str());
274 }
275 std::string unit;
276 r = sd_bus_creds_get_unit(creds, &u);
277 if (r >= 0)
278 {
279 unit = u;
280 }
281 else
282 {
283 printf("Oh! Could not get unit name for %s\n", unit.c_str());
284 }
285 printf("AddConnection %s %s %s %s %d\n", service.c_str(),
286 connection.c_str(), comm.c_str(), unit.c_str(), pid);
287 g_connection_snapshot->AddConnection(service, connection, comm, unit,
288 pid);
289 }
290 printf("There are %d DBus names.\n", int(services.size()));
291 for (int i = 0; i < int(services.size()); i++)
292 {
293 printf(" %d: %s [%s]\n", i, services[i].c_str(), comms[i].c_str());
294 }
295 g_sensor_snapshot = new SensorSnapshot(g_connection_snapshot);
296 // busctl call xyz.openbmc_project.ObjectMapper /
297 // org.freedesktop.DBus.Introspectable Introspect
298 printf("3. See which sensors are visible from Object Mapper\n");
299 printf("3.1. Introspect Object Mapper for object paths\n");
300 std::vector<std::string> all_obj_paths = FindAllObjectPathsForService(
301 "xyz.openbmc_project.ObjectMapper", nullptr);
302 sd_bus_error err = SD_BUS_ERROR_NULL;
303 sd_bus_message *m, *reply;
304 printf("%d paths found while introspecting ObjectMapper.\n",
305 int(all_obj_paths.size()));
306 printf("3.2. Call ObjectMapper's GetObject method against the sensor "
307 "object paths that represent sensors\n");
308 for (const std::string& p : all_obj_paths)
309 {
310 if (IsSensorObjectPath(p))
311 {
312 err = SD_BUS_ERROR_NULL;
313 r = sd_bus_message_new_method_call(
314 g_bus, &m, "xyz.openbmc_project.ObjectMapper",
315 "/xyz/openbmc_project/object_mapper",
316 "xyz.openbmc_project.ObjectMapper", "GetObject");
317 if (r < 0)
318 {
319 printf("Cannot create new method call. r=%d, strerror=%s\n", r,
320 strerror(-r));
321 continue;
322 }
323 r = sd_bus_message_append_basic(m, 's', p.c_str());
324 if (r < 0)
325 {
326 printf("Could not append a string parameter to m\n");
327 continue;
328 }
329 // empty array
330 r = sd_bus_message_open_container(m, 'a', "s");
331 if (r < 0)
332 {
333 printf("Could not open a container for m\n");
334 continue;
335 }
336 r = sd_bus_message_close_container(m);
337 if (r < 0)
338 {
339 printf("Could not close container for m\n");
340 continue;
341 }
342 r = sd_bus_call(g_bus, m, 0, &err, &reply);
343 if (r < 0)
344 {
345 printf("Error performing dbus method call\n");
346 }
347 const char* sig = sd_bus_message_get_signature(reply, 0);
348 if (!strcmp(sig, "a{sas}"))
349 {
350 r = sd_bus_message_enter_container(reply, 'a', "{sas}");
351 if (r < 0)
352 {
353 printf("Could not enter the level 0 array container\n");
354 continue;
355 }
356 while (true)
357 {
358 r = sd_bus_message_enter_container(
359 reply, SD_BUS_TYPE_DICT_ENTRY, "sas");
360 if (r < 0)
361 {
362 // printf("Could not enter the level 1 dict
363 // container\n");
364 goto DONE;
365 }
366 else if (r == 0)
367 {}
368 else
369 {
370 // The following 2 correspond to `interface_map` in
371 // phosphor-mapper
372 const char* interface_map_first;
373 r = sd_bus_message_read_basic(reply, 's',
374 &interface_map_first);
375 if (r < 0)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000376 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800377 printf("Could not read interface_map_first\n");
378 goto DONE;
379 }
380 r = sd_bus_message_enter_container(reply, 'a', "s");
381 if (r < 0)
382 {
383 printf("Could not enter the level 2 array "
384 "container\n");
385 goto DONE;
386 }
387 bool has_value_interface = false;
388 while (true)
389 {
390 const char* interface_map_second;
391 r = sd_bus_message_read_basic(
392 reply, 's', &interface_map_second);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000393 if (r < 0)
394 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800395 printf("Could not read interface_map_second\n");
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000396 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800397 else if (r == 0)
398 break;
399 else
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000400 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800401 // printf(" %s\n", interface_map_second);
402 if (!strcmp(interface_map_second,
403 "xyz.openbmc_project.Sensor.Value"))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000404 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800405 has_value_interface = true;
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000406 }
407 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800408 }
409 if (has_value_interface)
410 {
411 g_sensor_snapshot->SerSensorVisibleFromObjectMapper(
412 std::string(interface_map_first), p);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000413 }
414 r = sd_bus_message_exit_container(reply);
415 }
416 r = sd_bus_message_exit_container(reply);
417 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800418 r = sd_bus_message_exit_container(reply);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000419 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800420 DONE:
421 {}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000422 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800423 }
424 printf("4. Check Hwmon's DBus objects\n");
425 for (int i = 0; i < int(comms.size()); i++)
426 {
427 const std::string& comm = comms[i];
428 const std::string& service = services[i];
429 if (comm.find("phosphor-hwmon-readd") != std::string::npos &&
430 !IsUniqueName(service))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000431 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800432 // printf("Should introspect %s\n", service.c_str());
433 std::vector<std::string> objpaths =
434 FindAllObjectPathsForService(service, nullptr);
435 for (const std::string& op : objpaths)
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000436 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800437 if (IsSensorObjectPath(op))
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000438 {
kuiyingdfb0cd92023-03-14 11:43:23 +0800439 g_sensor_snapshot->SetSensorVisibleFromHwmon(service, op);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000440 }
441 }
442 }
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000443 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800444 // Call `ipmitool sdr list` and see which sensors exist.
445 printf("5. Checking ipmitool SDR List\n");
446 std::string out;
447 bool skip_sdr_list = false;
448 if (getenv("SKIP"))
449 {
450 skip_sdr_list = true;
451 }
452 if (!skip_sdr_list)
453 {
454 constexpr int MAX_BUFFER = 255;
455 char buffer[MAX_BUFFER];
456 FILE* stream = popen("ipmitool sdr list", "r");
457 while (fgets(buffer, MAX_BUFFER, stream) != NULL)
458 {
459 out.append(buffer);
460 }
461 pclose(stream);
462 }
463 std::stringstream ss(out);
464 while (true)
465 {
466 std::string sensor_id, reading, status;
467 std::getline(ss, sensor_id, '|');
468 std::getline(ss, reading, '|');
469 std::getline(ss, status);
470 // printf("%s %s %s\n", sensor_id.c_str(), reading.c_str(),
471 // status.c_str());
472 if (sensor_id.size() > 0 && reading.size() > 0 && status.size() > 0)
473 {
474 g_sensor_snapshot->SetSensorVisibleFromIpmitoolSdr(Trim(sensor_id));
475 }
476 else
477 break;
478 }
479 printf("=== Sensors snapshot summary: ===\n");
480 g_sensor_snapshot->PrintSummary();
481}
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000482} // namespace dbus_top_analyzer
483
484void DBusTopStatistics::OnNewDBusMessage(const char* sender,
485 const char* destination,
486 const char* interface,
487 const char* path, const char* member,
488 const char type, sd_bus_message* m)
489{
490 num_messages_++;
491 std::vector<std::string> keys;
492
493 std::string sender_orig = CheckAndFixNullString(sender);
494 std::string dest_orig = CheckAndFixNullString(destination);
495 // For method return messages, we actually want to show the sender
496 // and destination of the original method call, so we swap the
497 // sender and destination
498 if (type == 2)
499 { // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
500 std::swap(sender_orig, dest_orig);
501 }
502
503 // Special case: when PID == 1 (init), the DBus unit would be systemd.
504 // It seems it was not possible to obtain the connection name of systemd
505 // so we manually set it here.
506 const int sender_orig_pid =
507 g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(
508 sender_orig);
509
510 if (sender_orig_pid == 1)
511 {
512 sender_orig = "systemd";
513 }
514 const int dest_orig_pid =
515 g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(dest_orig);
516 if (dest_orig_pid == 1)
517 {
518 dest_orig = "systemd";
519 }
520
521 for (DBusTopSortField field : fields_)
522 {
523 switch (field)
524 {
525 case kSender:
526 keys.push_back(sender_orig);
527 break;
528 case kDestination:
529 keys.push_back(dest_orig);
530 break;
531 case kInterface:
532 keys.push_back(CheckAndFixNullString(interface));
533 break;
534 case kPath:
535 keys.push_back(CheckAndFixNullString(path));
536 break;
537 case kMember:
538 keys.push_back(CheckAndFixNullString(member));
539 break;
540 case kSenderPID:
541 {
542 if (sender_orig_pid != INVALID)
543 {
544 keys.push_back(std::to_string(sender_orig_pid));
545 }
546 else
547 {
548 keys.push_back("(unknown)");
549 }
550 break;
551 }
552 case kSenderCMD:
553 {
554 keys.push_back(
555 g_connection_snapshot->GetConnectionCMDFromNameOrUniqueName(
556 sender_orig));
557 break;
558 }
559 case kMsgPerSec:
560 case kAverageLatency:
561 break; // Don't populate "keys" using these 2 fields
562 }
563 }
564 // keys = combination of fields of user's choice
565
566 if (stats_.count(keys) == 0)
567 {
568 stats_[keys] = DBusTopComputedMetrics();
569 }
570 // Need to update msg/s regardless
571 switch (type)
572 {
573 case 1: // DBUS_MESSAGE_TYPE_METHOD_CALL
574 stats_[keys].num_method_calls++;
575 break;
576 case 2: // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
577 stats_[keys].num_method_returns++;
578 break;
579 case 3: // DBUS_MESSAGE_TYPE_ERROR
580 stats_[keys].num_errors++;
581 break;
582 case 4: // DBUS_MESSAGE_TYPE_SIGNAL
583 stats_[keys].num_signals++;
584 break;
585 }
586 // Update global latency histogram
587 // For method call latency
588 if (type == 1) // DBUS_MESSAGE_TYPE_METHOD_CALL
589 {
590 uint64_t serial; // serial == cookie
591 sd_bus_message_get_cookie(m, &serial);
592 in_flight_methodcalls[serial] = Microseconds();
593 }
594 else if (type == 2) // DBUS_MESSAGE_TYPE_MEHOTD_RETURN
595 {
596 uint64_t reply_serial = 0; // serial == cookie
597 sd_bus_message_get_reply_cookie(m, &reply_serial);
598 if (in_flight_methodcalls.count(reply_serial) > 0)
599 {
600 float dt_usec =
601 Microseconds() - in_flight_methodcalls[reply_serial];
602 in_flight_methodcalls.erase(reply_serial);
603 dbus_top_analyzer::g_mc_time_histogram.AddSample(dt_usec);
604
605 // Add method call count and total latency to the corresponding key
606 stats_[keys].total_latency_usec += dt_usec;
607 }
608 }
609 // For meaning of type see here
610 // https://dbus.freedesktop.org/doc/api/html/group__DBusProtocol.html#ga4a9012edd7f22342f845e98150aeb858
611 switch (type)
612 {
613 case 1:
614 num_mc_++;
615 break;
616 case 2:
617 num_mr_++;
618 break;
619 case 3:
620 num_error_++;
621 break;
622 case 4:
623 num_sig_++;
624 break;
625 }
626}