dbus-top: remove dbus-top from openbmc-tools
dbus-top has "graduated" from openbmc-tools and existing code has been
migrated to https://github.com/openbmc/dbus-top, so removing its folder
from openbmc-tools.
Signed-off-By: Sui Chen <suichen@google.com>
Change-Id: I1bccd8c01aa24f26b9904d5d5e7ae14205df5a84
diff --git a/dbus-top/.clang-format b/dbus-top/.clang-format
deleted file mode 100644
index 3652c56..0000000
--- a/dbus-top/.clang-format
+++ /dev/null
@@ -1,113 +0,0 @@
----
-Language: Cpp
-# BasedOnStyle: LLVM
-AccessModifierOffset: -2
-AlignAfterOpenBracket: Align
-AlignConsecutiveAssignments: false
-AlignConsecutiveDeclarations: false
-AlignEscapedNewlines: Right
-AlignOperands: true
-AlignTrailingComments: true
-AllowAllParametersOfDeclarationOnNextLine: true
-AllowShortBlocksOnASingleLine: false
-AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: None
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
-AlwaysBreakTemplateDeclarations: Yes
-BinPackArguments: true
-BinPackParameters: true
-BraceWrapping:
- AfterCaseLabel: true
- AfterClass: true
- AfterControlStatement: true
- AfterEnum: true
- AfterFunction: true
- AfterNamespace: true
- AfterObjCDeclaration: true
- AfterStruct: true
- AfterUnion: true
- AfterExternBlock: true
- BeforeCatch: true
- BeforeElse: true
- IndentBraces: false
- SplitEmptyFunction: false
- SplitEmptyRecord: false
- SplitEmptyNamespace: false
-BreakBeforeBinaryOperators: None
-BreakBeforeBraces: Custom
-BreakBeforeTernaryOperators: true
-BreakConstructorInitializers: AfterColon
-BreakInheritanceList: AfterColon
-BreakStringLiterals: true
-ColumnLimit: 80
-CommentPragmas: '^ IWYU pragma:'
-CompactNamespaces: false
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-ConstructorInitializerIndentWidth: 4
-ContinuationIndentWidth: 4
-Cpp11BracedListStyle: true
-DerivePointerAlignment: false
-PointerAlignment: Left
-DisableFormat: false
-ExperimentalAutoDetectBinPacking: false
-FixNamespaceComments: true
-ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
-IncludeBlocks: Regroup
-IncludeCategories:
- - Regex: '^[<"](gtest|gmock)'
- Priority: 7
- - Regex: '^"config.h"'
- Priority: -1
- - Regex: '^".*\.h"'
- Priority: 1
- - Regex: '^".*\.hpp"'
- Priority: 2
- - Regex: '^<.*\.h>'
- Priority: 3
- - Regex: '^<.*\.hpp>'
- Priority: 4
- - Regex: '^<.*'
- Priority: 5
- - Regex: '.*'
- Priority: 6
-IndentCaseLabels: true
-IndentWidth: 4
-IndentWrappedFunctionNames: true
-KeepEmptyLinesAtTheStartOfBlocks: true
-MacroBlockBegin: ''
-MacroBlockEnd: ''
-MaxEmptyLinesToKeep: 1
-NamespaceIndentation: None
-ObjCBlockIndentWidth: 2
-ObjCSpaceAfterProperty: false
-ObjCSpaceBeforeProtocolList: true
-PenaltyBreakBeforeFirstCallParameter: 19
-PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
-PenaltyBreakString: 1000
-PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 60
-ReflowComments: true
-SortIncludes: true
-SortUsingDeclarations: true
-SpaceAfterCStyleCast: false
-SpaceAfterTemplateKeyword: true
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeCpp11BracedList: false
-SpaceBeforeCtorInitializerColon: true
-SpaceBeforeInheritanceColon: true
-SpaceBeforeParens: ControlStatements
-SpaceBeforeRangeBasedForLoopColon: true
-SpaceInEmptyParentheses: false
-SpacesBeforeTrailingComments: 1
-SpacesInAngles: false
-SpacesInContainerLiterals: true
-SpacesInCStyleCastParentheses: false
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-Standard: Latest
-TabWidth: 4
-UseTab: Never
diff --git a/dbus-top/.gitignore b/dbus-top/.gitignore
deleted file mode 100644
index a2ae220..0000000
--- a/dbus-top/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-oe-logs
-oe-workdir
-.vscode
diff --git a/dbus-top/README.md b/dbus-top/README.md
deleted file mode 100644
index b7be655..0000000
--- a/dbus-top/README.md
+++ /dev/null
@@ -1,214 +0,0 @@
-# Design Doc for dbus-top
-
-Author: Adedeji Adebisi (ziniblessed@google.com)
-
-Primary Assignee: Adedeji Adebisi
-
-Other contributors: Sui Chen (suichen@google.com) Alex Qiu (xqiu@google.com)
-
-Created: May 17, 2021
-
-## Problem Description
-
-Design and Implementation of a top-like tool for DBus. This tool shows metrics
-related to dbus connections such as message throughput, as well as system
-information available through DBus such as the list of sensors, in an attempt to
-understand some performance related issues on the BMC. The sensor information is
-extracted from well-known DBus services such as the Object Mapper, Inventory
-Manager, and Entity Manager. DBus-top shows the information conveniently that
-might otherwise require the user to type long commands or scripts.
-
-## Background and References
-
-This tool adds to the set of command-line based tools that run directly on the
-BMC. Using a tool that directly runs on the BMC, a user can debug problems
-in-situ, without needing to extract data from the BMC to the host for offline
-analysis. This tool resembles a typical top-like user interface, giving the user
-a top-down view of various DBus states. This tool is designed in the same logic
-as similarly-purposed, existing tools, each focusing on one particular field
-such as ctop (for containers), htop (for viewing process stats), iotop (for I/O
-throughput), iftop (for network traffic).
-
-## Requirements
-
-Constraints:
-
-1. BMC consoles may not be capable of displaying all text styles supported in
- ncurses Dependency on libncurses which might add ~130KB overhead to the BMC’s
- Flash space.
-2. Monitoring DBus should not incur so much performance overhead as to distort
- measured values.
-3. Users are OpenBMC users and developers: This tool should help beginners learn
- the basics of OpenBMC, as well as help seasoned developers quickly locate a
- problem.
-
-Scope:
-
-1. This tool is standalone, self-sufficient, with minimum dependency on existing
- software packages (only depends on basic packages like systemd, libdbus,
- sdbus, sdbusplus, and libncurses.) Data size, transaction rates, bandwidth:
- We will be looking at typically hundreds of DBus messages per second and
- around 1 MB/s data throughput. The BMC’s processing power and memory capacity
- are sufficient for the scale of the data this tool is processing.
-2. This tool should work on a live DBus as well as on a capture file (a pcap
- file).
-3. This tool should work both on the host or the BMC. The UI design is scaled to
- work with large numbers of sensors and different console sizes.
-
-## Proposed Design
-
-The proposed design is to layout a multi-window UI similar to how a tiled window
-manager does:
-
-```text
-+----------------------------------------------------------------------------+
-|Message Type | msg/s History (Total msg/s) |
-|Method Call 45.00 - . . . . -2300 |
-|Method Return 45.00 - : : : : -1750 |
-|Signal 53.00 - : : : : -1200 |
-|Error 0.00 - : : : : -650 |
-|Total 142.99 -:::.....:::.....:::.....:::....-100 |
-+-------------------------------------+--------------------------------------+
-| Columns 1-2 of 6 84 sensors | Msg/s Sender Destination |
-| vddq_efgh_out vddcr_cpu1_in | 7.50 :1.14 :1.48 |
-| vddcr_cpu0_out vddcr_soc1_out | 7.50 :1.14 org.freedesktop.DB>|
-| vddq_mnop_out vddq_efgh_in | 7.50 :1.48 :1.52 |
-| vddcr_soc0_out vddq_abcd_in | 7.50 :1.48 org.freedesktop.DB>|
-| vddq_ijkl_in vddq_efgh_out | 1.00 :1.48 xyz.openbmc_projec>|
-| vddcr_soc0_in hotswap_pout | 1.00 :1.48 xyz.openbmc_projec>|
-| vddcr_cpu0_in vddcr_cpu1_in | 1.00 :1.48 xyz.openbmc_projec>|
-| vddq_ijkl_out vddq_efgh_in | 5.00 :1.48 xyz.openbmc_projec>|
-| vddcr_soc1_in vddq_ijkl_out | 5.00 :1.48 xyz.openbmc_projec>|
-| hotswap_iout vddcr_soc0_out | 1.00 :1.48 xyz.openbmc_projec>|
-| vddq_abcd_in vddcr_soc1_in | 7.50 :1.48 xyz.openbmc_projec>|
-| vddq_mnop_in vddq_mnop_in | 7.50 :1.52 xyz.openbmc_projec>|
-| vddcr_cpu1_out vddcr_cpu1_out | 1.00 :1.70 (null) |
-| vddq_abcd_out vddcr_cpu0_out | 1.00 :1.70 :1.48 |
-+-------------------------------------+--------------------------------------+
- Fri Jul 2 15:50:08 2021 PRESS ? FOR HELP
-```
-
-The UI has 3 windows:
-
-### Top, summary window
-
-This window is divided into two sections:
-
-- The dbus traffic dump that shows the method calls, method returns,signals and
- errors in every dbus callback. This is significant because it shows the
- latency between every call back and the other section that shows the graph can
- benefit from this.
-- The other part shows a history graph of these corresponding data and it is
- designed this way to show users a pictorial representation of the callback
- metrics.
-
-### Bottom-left, sensor detail window
-
-This window has two states:
-
-- The window shows the list of all sensors (as defined by DBus objects
- implementing the xyz.openbmc_project.Sensor.Value) by default
-- When a sensor is selected, it shows the corresponding details including sensor
- name, the dbus connection, PID and the dbus service associated with the
- sensor. This will be helpful in understanding what is connected to the sensor
- in a case of performance related to the sensor.
-
-The following is how the window might look once a sensor has been selected:
-
-```text
-+-------------------------------------------------+
-| Details for sensor cputemp0 Sensor 1/192 |
-| [DBus Info] |
-| DBus Connection : :1.234 |
-| DBus Service : xyz.openbmc_project... |
-| DBus Object Path: /path/to/object |
-| |
-| [Inventory Info] |
-| Association: |
-| - chassis: all_sensors |
-| |
-| [Visibility] |
-| - IPMI SEL: Yes |
-| - Object Mapper: Yes |
-| - Sensor Daemon: Yes |
-+-------------------------------------------------+
-```
-
-### Bottom-right, DBus stats list view window
-
-This window shows the stats of DBus connections in a list, aggregated by the
-fields of the user’s choice. These fields include sender, destination, path,
-interface, and message type.
-
-A menu is available that allows the user to select what fields to use to
-aggregate the entries in the window.
-
-```text
-+----------------------------------------+
-|Available Fields Active Fields |
-| |
-|Interface Sender |
-|Path ---> Destination |
-|Message Type <--- |
-|Sender Process Name |
-+----------------------------------------+
-```
-
-The windows can be resized, or shown/hidden individually.
-
-Overview of the Program Structure:
-
-```text
- UI Thread Analysis Thread Capture Thread
- _______^_______ _________^__________ _________^______
- / \ / \ / \
-
- +-+-------+ +----------+ +-------+ +-----------+
-+-----+ | |User | | Call | ,-|Message|<-. |Become |
-|User | | |Setting|-. S | ObjMapper| | |Handler| |M |DBus |
-|Input| | `-------+ | o | Inv.Mgr | | +-------+ |eD |Monitor |
-+-----+ | | |Kr | EntityMgr| | | |sB +-----------+
- | |Frontend | |et +----------+ | V |su |
- `----->| UI | |y | | +-------+ |as V
- Key | | |s `----------->|Method | |g +------------+
- Stroke | | `-->+---------+ | |Call | |e |DBus Capture|
- | |<-. |Aggregate| | |Tracker| |s +------------+
- +---------+ | | |<-' +-------+ | |
- | | | +---------+ | +------'
- V V | | | |
- +--------+ +-----+ | V V |
- |ncurses-| |Text-| | +-------+ +-------+ | +-----------+
- |based | |based| +---|Sensor | |Sensor | `---|PCAP Replay|
- |UI | |UI | | |Stats | |Details| +-----------+
- +--------+ +-----+ | +-------+ +-------+
- | |
- `---------------------'
-```
-
-## Alternatives Considered
-
-Non-Curses UI: This would help avoid dependence on libncurses, which some BMCs
-might not have. However, we expect libncurses to be present on most BMCs because
-it is widely used in most TUIs.
-
-## Impacts
-
-API impact: none
-
-Security impact: Being confirmed.
-
-Performance impact: Will only have a small impact when the program is running.
-No impact when it’s not running.
-
-Developer impact: For machines that do not install libncurses by default, adding
-this tool might incur a ~130KB overhead due to the libncurses library. No space
-overhead if the machine already includes libncurses.
-
-## Testing
-
-Individual functionalities will be tested with unit tests.
-
-Functional tests will be done using PCAP files.
-
-CI testing is not affected since it doesn’t modify the build process of any
-other package.
diff --git a/dbus-top/analyzer.cpp b/dbus-top/analyzer.cpp
deleted file mode 100644
index f31868c..0000000
--- a/dbus-top/analyzer.cpp
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "analyzer.hpp"
-#include "histogram.hpp"
-#include "main.hpp"
-#include "sensorhelper.hpp"
-#include "views.hpp"
-#include "xmlparse.hpp"
-
-#include <unistd.h>
-#include <atomic>
-#include <filesystem>
-#include <fstream>
-#include <functional>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-extern SensorSnapshot* g_sensor_snapshot;
-extern DBusConnectionSnapshot* g_connection_snapshot;
-extern sd_bus* g_bus;
-extern SensorDetailView* g_sensor_detail_view;
-
-static std::unordered_map<uint64_t, uint64_t>
- in_flight_methodcalls; // serial => microseconds
-uint64_t Microseconds()
-{
- long us; // usec
- time_t s; // Seconds
- struct timespec spec;
- clock_gettime(CLOCK_REALTIME, &spec);
- s = spec.tv_sec;
- us = round(spec.tv_nsec / 1000); // Convert nanoseconds to milliseconds
- if (us > 999999)
- {
- s++;
- us = 0;
- }
- return s * 1000000 + us;
-}
-
-int g_update_interval_millises = 2000;
-int GetSummaryIntervalInMillises()
-{
- return g_update_interval_millises;
-}
-
-bool DBusTopSortFieldIsNumeric(DBusTopSortField field)
-{
- switch (field)
- {
- case kSender:
- case kDestination:
- case kInterface:
- case kPath:
- case kMember:
- case kSenderCMD:
- return false;
- case kSenderPID:
- case kMsgPerSec:
- case kAverageLatency:
- return true;
- }
- return false;
-}
-
-namespace dbus_top_analyzer
-{
- DBusTopStatistics g_dbus_statistics;
- Histogram<float> g_mc_time_histogram;
- std::unordered_map<uint32_t, uint64_t> in_flight_methodcalls;
- std::atomic<bool> g_program_done = false;
- std::chrono::time_point<std::chrono::steady_clock> g_last_update;
- DBusTopStatisticsCallback g_callback;
- void SetDBusTopStatisticsCallback(DBusTopStatisticsCallback cb)
- {
- g_callback = cb;
- }
-
- int UserInputThread()
- {
- return 0;
- }
-
- std::string g_dbus_top_conn = " ";
- void SetDBusTopConnectionForMonitoring(const std::string& conn)
- {
- g_dbus_top_conn = conn;
- }
-
- // Performs one step of analysis
- void Process()
- {
- std::chrono::time_point<std::chrono::steady_clock> t =
- std::chrono::steady_clock::now();
- std::chrono::time_point<std::chrono::steady_clock> next_update =
- g_last_update + std::chrono::milliseconds(g_update_interval_millises);
- if (t >= next_update)
- {
- float seconds_since_last_sample =
- std::chrono::duration_cast<std::chrono::microseconds>(t -
- g_last_update)
- .count() /
- 1000000.0f;
- g_dbus_statistics.seconds_since_last_sample_ =
- seconds_since_last_sample;
- // Update snapshot
- if (g_callback)
- {
- g_callback(&g_dbus_statistics, &g_mc_time_histogram);
- }
- g_dbus_statistics.Reset();
- g_last_update = t;
- }
- }
-
- void Finish()
- {
- g_program_done = true;
- }
-
- std::vector<std::string> FindAllObjectPathsForService(
- const std::string& service,
- std::function<void(const std::string&, const std::vector<std::string>&)>
- on_interface_cb)
- {
- sd_bus_error err = SD_BUS_ERROR_NULL;
- sd_bus_message *m, *reply;
- std::vector<std::string> paths; // Current iteration
- std::vector<std::string>
- all_obj_paths; // All object paths under the supervision of ObjectMapper
- paths.push_back("/");
- // busctl call xyz.openbmc_project.ObjectMapper /
- // org.freedesktop.DBus.Introspectable Introspect
- while (!paths.empty())
- {
- // printf("%d paths to explore, total %d paths so far\n",
- // int(paths.size()), int(all_obj_paths.size()));
- std::vector<std::string> new_paths;
- for (const std::string& obj_path : paths)
- {
- all_obj_paths.push_back(obj_path);
- int r = sd_bus_message_new_method_call(
- g_bus, &m, service.c_str(), obj_path.c_str(),
- "org.freedesktop.DBus.Introspectable", "Introspect");
- if (r < 0)
- {
- printf("Oh! Cannot create new method call. r=%d, strerror=%s\n",
- r, strerror(-r));
- continue;
- }
- r = sd_bus_call(g_bus, m, 0, &err, &reply);
- if (r < 0)
- {
- printf("Could not execute method call, r=%d, strerror=%s\n", r,
- strerror(-r));
- }
- const char* sig = sd_bus_message_get_signature(reply, 0);
- if (!strcmp(sig, "s"))
- {
- const char* s;
- int r = sd_bus_message_read(reply, "s", &s);
- std::string s1(s);
- if (r < 0)
- {
- printf("Could not read string payload, r=%d, strerror=%s\n",
- r, strerror(-r));
- }
- else
- {
- XMLNode* t = ParseXML(s1);
- std::vector<std::string> ch = t->GetChildNodeNames();
- if (on_interface_cb != nullptr)
- {
- on_interface_cb(obj_path, t->GetInterfaceNames());
- }
- DeleteTree(t);
- for (const std::string& cn : ch)
- {
- std::string ch_path = obj_path;
- if (obj_path.back() == '/')
- {}
- else
- ch_path.push_back('/');
- ch_path += cn;
- new_paths.push_back(ch_path);
- }
- }
- }
- }
- paths = new_paths;
- }
- return all_obj_paths;
- }
-
- void ListAllSensors()
- {
- g_connection_snapshot = new DBusConnectionSnapshot();
- printf("1. Getting names\n");
- char** names;
- int r = sd_bus_list_names(g_bus, &names, nullptr);
- std::vector<std::string> services;
- std::vector<int> pids;
- std::vector<std::string> comms;
- for (char** ptr = names; ptr && *ptr; ++ptr)
- {
- services.push_back(*ptr);
- free(*ptr);
- }
- free(names);
- printf("2. Getting creds of each name\n");
- for (int i = 0; i < static_cast<int>(services.size()); i++)
- {
- const std::string& service = services[i];
- sd_bus_creds* creds = nullptr;
- r = sd_bus_get_name_creds(g_bus, services[i].c_str(),
- SD_BUS_CREDS_AUGMENT | SD_BUS_CREDS_EUID |
- SD_BUS_CREDS_PID | SD_BUS_CREDS_COMM |
- SD_BUS_CREDS_UNIQUE_NAME |
- SD_BUS_CREDS_UNIT | SD_BUS_CREDS_SESSION |
- SD_BUS_CREDS_DESCRIPTION,
- &creds);
- // PID
- int pid = INVALID;
- if (r < 0)
- {
- printf("Oh! Cannot get creds for %s\n", services[i].c_str());
- }
- else
- {
- r = sd_bus_creds_get_pid(creds, &pid);
- }
- pids.push_back(pid);
- // comm
- std::string comm;
- if (pid != INVALID)
- {
- std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
- std::string line;
- std::getline(ifs, line);
- for (char c : line)
- {
- if (c < 32 || c >= 127)
- c = ' ';
- comm.push_back(c);
- }
- }
- comms.push_back(comm);
- // unique name, also known as "Connection"
- std::string connection;
- const char* u;
- r = sd_bus_creds_get_unique_name(creds, &u);
- if (r >= 0)
- {
- connection = u;
- }
- else
- {
- printf("Oh! Could not get unique name for %s\n", service.c_str());
- }
- std::string unit;
- r = sd_bus_creds_get_unit(creds, &u);
- if (r >= 0)
- {
- unit = u;
- }
- else
- {
- printf("Oh! Could not get unit name for %s\n", unit.c_str());
- }
- printf("AddConnection %s %s %s %s %d\n", service.c_str(),
- connection.c_str(), comm.c_str(), unit.c_str(), pid);
- g_connection_snapshot->AddConnection(service, connection, comm, unit,
- pid);
- }
- printf("There are %d DBus names.\n", int(services.size()));
- for (int i = 0; i < int(services.size()); i++)
- {
- printf(" %d: %s [%s]\n", i, services[i].c_str(), comms[i].c_str());
- }
- g_sensor_snapshot = new SensorSnapshot(g_connection_snapshot);
- // busctl call xyz.openbmc_project.ObjectMapper /
- // org.freedesktop.DBus.Introspectable Introspect
- printf("3. See which sensors are visible from Object Mapper\n");
- printf("3.1. Introspect Object Mapper for object paths\n");
- std::vector<std::string> all_obj_paths = FindAllObjectPathsForService(
- "xyz.openbmc_project.ObjectMapper", nullptr);
- sd_bus_error err = SD_BUS_ERROR_NULL;
- sd_bus_message *m, *reply;
- printf("%d paths found while introspecting ObjectMapper.\n",
- int(all_obj_paths.size()));
- printf("3.2. Call ObjectMapper's GetObject method against the sensor "
- "object paths that represent sensors\n");
- for (const std::string& p : all_obj_paths)
- {
- if (IsSensorObjectPath(p))
- {
- err = SD_BUS_ERROR_NULL;
- r = sd_bus_message_new_method_call(
- g_bus, &m, "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject");
- if (r < 0)
- {
- printf("Cannot create new method call. r=%d, strerror=%s\n", r,
- strerror(-r));
- continue;
- }
- r = sd_bus_message_append_basic(m, 's', p.c_str());
- if (r < 0)
- {
- printf("Could not append a string parameter to m\n");
- continue;
- }
- // empty array
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- {
- printf("Could not open a container for m\n");
- continue;
- }
- r = sd_bus_message_close_container(m);
- if (r < 0)
- {
- printf("Could not close container for m\n");
- continue;
- }
- r = sd_bus_call(g_bus, m, 0, &err, &reply);
- if (r < 0)
- {
- printf("Error performing dbus method call\n");
- }
- const char* sig = sd_bus_message_get_signature(reply, 0);
- if (!strcmp(sig, "a{sas}"))
- {
- r = sd_bus_message_enter_container(reply, 'a', "{sas}");
- if (r < 0)
- {
- printf("Could not enter the level 0 array container\n");
- continue;
- }
- while (true)
- {
- r = sd_bus_message_enter_container(
- reply, SD_BUS_TYPE_DICT_ENTRY, "sas");
- if (r < 0)
- {
- // printf("Could not enter the level 1 dict
- // container\n");
- goto DONE;
- }
- else if (r == 0)
- {}
- else
- {
- // The following 2 correspond to `interface_map` in
- // phosphor-mapper
- const char* interface_map_first;
- r = sd_bus_message_read_basic(reply, 's',
- &interface_map_first);
- if (r < 0)
- {
- printf("Could not read interface_map_first\n");
- goto DONE;
- }
- r = sd_bus_message_enter_container(reply, 'a', "s");
- if (r < 0)
- {
- printf("Could not enter the level 2 array "
- "container\n");
- goto DONE;
- }
- bool has_value_interface = false;
- while (true)
- {
- const char* interface_map_second;
- r = sd_bus_message_read_basic(
- reply, 's', &interface_map_second);
- if (r < 0)
- {
- printf("Could not read interface_map_second\n");
- }
- else if (r == 0)
- break;
- else
- {
- // printf(" %s\n", interface_map_second);
- if (!strcmp(interface_map_second,
- "xyz.openbmc_project.Sensor.Value"))
- {
- has_value_interface = true;
- }
- }
- }
- if (has_value_interface)
- {
- g_sensor_snapshot->SerSensorVisibleFromObjectMapper(
- std::string(interface_map_first), p);
- }
- r = sd_bus_message_exit_container(reply);
- }
- r = sd_bus_message_exit_container(reply);
- }
- r = sd_bus_message_exit_container(reply);
- }
- DONE:
- {}
- }
- }
- printf("4. Check Hwmon's DBus objects\n");
- for (int i = 0; i < int(comms.size()); i++)
- {
- const std::string& comm = comms[i];
- const std::string& service = services[i];
- if (comm.find("phosphor-hwmon-readd") != std::string::npos &&
- !IsUniqueName(service))
- {
- // printf("Should introspect %s\n", service.c_str());
- std::vector<std::string> objpaths =
- FindAllObjectPathsForService(service, nullptr);
- for (const std::string& op : objpaths)
- {
- if (IsSensorObjectPath(op))
- {
- g_sensor_snapshot->SetSensorVisibleFromHwmon(service, op);
- }
- }
- }
- }
- // Call `ipmitool sdr list` and see which sensors exist.
- printf("5. Checking ipmitool SDR List\n");
- std::string out;
- bool skip_sdr_list = false;
- if (getenv("SKIP"))
- {
- skip_sdr_list = true;
- }
- if (!skip_sdr_list)
- {
- constexpr int MAX_BUFFER = 255;
- char buffer[MAX_BUFFER];
- FILE* stream = popen("ipmitool sdr list", "r");
- while (fgets(buffer, MAX_BUFFER, stream) != NULL)
- {
- out.append(buffer);
- }
- pclose(stream);
- }
- std::stringstream ss(out);
- while (true)
- {
- std::string sensor_id, reading, status;
- std::getline(ss, sensor_id, '|');
- std::getline(ss, reading, '|');
- std::getline(ss, status);
- // printf("%s %s %s\n", sensor_id.c_str(), reading.c_str(),
- // status.c_str());
- if (sensor_id.size() > 0 && reading.size() > 0 && status.size() > 0)
- {
- g_sensor_snapshot->SetSensorVisibleFromIpmitoolSdr(Trim(sensor_id));
- }
- else
- break;
- }
- printf("=== Sensors snapshot summary: ===\n");
- g_sensor_snapshot->PrintSummary();
- }
-} // namespace dbus_top_analyzer
-
-void DBusTopStatistics::OnNewDBusMessage(const char* sender,
- const char* destination,
- const char* interface,
- const char* path, const char* member,
- const char type, sd_bus_message* m)
-{
- num_messages_++;
- std::vector<std::string> keys;
-
- std::string sender_orig = CheckAndFixNullString(sender);
- std::string dest_orig = CheckAndFixNullString(destination);
- // For method return messages, we actually want to show the sender
- // and destination of the original method call, so we swap the
- // sender and destination
- if (type == 2)
- { // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
- std::swap(sender_orig, dest_orig);
- }
-
- // Special case: when PID == 1 (init), the DBus unit would be systemd.
- // It seems it was not possible to obtain the connection name of systemd
- // so we manually set it here.
- const int sender_orig_pid =
- g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(
- sender_orig);
-
- if (sender_orig_pid == 1)
- {
- sender_orig = "systemd";
- }
- const int dest_orig_pid =
- g_connection_snapshot->GetConnectionPIDFromNameOrUniqueName(dest_orig);
- if (dest_orig_pid == 1)
- {
- dest_orig = "systemd";
- }
-
- for (DBusTopSortField field : fields_)
- {
- switch (field)
- {
- case kSender:
- keys.push_back(sender_orig);
- break;
- case kDestination:
- keys.push_back(dest_orig);
- break;
- case kInterface:
- keys.push_back(CheckAndFixNullString(interface));
- break;
- case kPath:
- keys.push_back(CheckAndFixNullString(path));
- break;
- case kMember:
- keys.push_back(CheckAndFixNullString(member));
- break;
- case kSenderPID:
- {
- if (sender_orig_pid != INVALID)
- {
- keys.push_back(std::to_string(sender_orig_pid));
- }
- else
- {
- keys.push_back("(unknown)");
- }
- break;
- }
- case kSenderCMD:
- {
- keys.push_back(
- g_connection_snapshot->GetConnectionCMDFromNameOrUniqueName(
- sender_orig));
- break;
- }
- case kMsgPerSec:
- case kAverageLatency:
- break; // Don't populate "keys" using these 2 fields
- }
- }
- // keys = combination of fields of user's choice
-
- if (stats_.count(keys) == 0)
- {
- stats_[keys] = DBusTopComputedMetrics();
- }
- // Need to update msg/s regardless
- switch (type)
- {
- case 1: // DBUS_MESSAGE_TYPE_METHOD_CALL
- stats_[keys].num_method_calls++;
- break;
- case 2: // DBUS_MESSAGE_TYPE_METHOD_METHOD_RETURN
- stats_[keys].num_method_returns++;
- break;
- case 3: // DBUS_MESSAGE_TYPE_ERROR
- stats_[keys].num_errors++;
- break;
- case 4: // DBUS_MESSAGE_TYPE_SIGNAL
- stats_[keys].num_signals++;
- break;
- }
- // Update global latency histogram
- // For method call latency
- if (type == 1) // DBUS_MESSAGE_TYPE_METHOD_CALL
- {
- uint64_t serial; // serial == cookie
- sd_bus_message_get_cookie(m, &serial);
- in_flight_methodcalls[serial] = Microseconds();
- }
- else if (type == 2) // DBUS_MESSAGE_TYPE_MEHOTD_RETURN
- {
- uint64_t reply_serial = 0; // serial == cookie
- sd_bus_message_get_reply_cookie(m, &reply_serial);
- if (in_flight_methodcalls.count(reply_serial) > 0)
- {
- float dt_usec =
- Microseconds() - in_flight_methodcalls[reply_serial];
- in_flight_methodcalls.erase(reply_serial);
- dbus_top_analyzer::g_mc_time_histogram.AddSample(dt_usec);
-
- // Add method call count and total latency to the corresponding key
- stats_[keys].total_latency_usec += dt_usec;
- }
- }
- // For meaning of type see here
- // https://dbus.freedesktop.org/doc/api/html/group__DBusProtocol.html#ga4a9012edd7f22342f845e98150aeb858
- switch (type)
- {
- case 1:
- num_mc_++;
- break;
- case 2:
- num_mr_++;
- break;
- case 3:
- num_error_++;
- break;
- case 4:
- num_sig_++;
- break;
- }
-}
diff --git a/dbus-top/analyzer.hpp b/dbus-top/analyzer.hpp
deleted file mode 100644
index 2284c7f..0000000
--- a/dbus-top/analyzer.hpp
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "histogram.hpp"
-
-#include <systemd/sd-bus.h>
-
-#include <atomic>
-#include <map>
-#include <mutex>
-#include <string>
-#include <vector>
-
-enum DBusTopSortField
-{
- // DBus Message properties
- kSender,
- kDestination,
- kInterface,
- kPath,
- kMember,
- kSenderPID,
- kSenderCMD,
- // Computed metrics
- kMsgPerSec,
- kAverageLatency,
-};
-
-const std::string FieldNames[] = {"Sender", "Destination", "Interface",
- "Path", "Member", "Sender PID",
- "Sender CMD", "Msg/s", "Avg Latency"};
-const int FieldPreferredWidths[] = {18, 20, 12, 10, 10, 10, 25, 8, 12};
-bool DBusTopSortFieldIsNumeric(DBusTopSortField field);
-
-struct DBusTopComputedMetrics
-{
- DBusTopComputedMetrics()
- {
- num_signals = 0;
- num_errors = 0;
- num_method_returns = 0;
- num_method_calls = 0;
- total_latency_usec = 0;
- }
- int num_method_returns = 0;
- int num_errors = 0;
- int num_signals = 0;
- int num_method_calls;
- uint64_t total_latency_usec;
-};
-
-class DBusTopStatistics
-{
- public:
- int num_messages_;
- int num_mc_, num_mr_, num_sig_, num_error_;
- float seconds_since_last_sample_;
- std::vector<DBusTopSortField> fields_;
- std::map<std::vector<std::string>, DBusTopComputedMetrics> stats_;
- DBusTopStatistics() :
- num_messages_(0), num_mc_(0), num_mr_(0), num_sig_(0), num_error_(0),
- seconds_since_last_sample_(0)
- {
- fields_ = {kSender, kDestination, kSenderPID, kSenderCMD};
- stats_.clear();
- }
-
- std::vector<DBusTopSortField> GetFields()
- {
- return fields_;
- }
-
- std::vector<std::string> GetFieldNames()
- {
- const int N = fields_.size();
- std::vector<std::string> ret(N);
- for (int i = 0; i < static_cast<int>(fields_.size()); i++)
- {
- ret[i] = FieldNames[static_cast<int>(fields_[i])];
- }
- return ret;
- }
-
- std::vector<int> GetFieldPreferredWidths()
- {
- const int N = fields_.size();
- std::vector<int> ret(N);
- for (int i = 0; i < static_cast<int>(fields_.size()); i++)
- {
- ret[i] = FieldPreferredWidths[static_cast<int>(fields_[i])];
- }
- return ret;
- }
-
- void Reset()
- {
- num_messages_ = 0;
- num_mc_ = 0;
- num_mr_ = 0;
- num_sig_ = 0;
- num_error_ = 0;
- stats_.clear();
- }
-
- void SetSortFieldsAndReset(const std::vector<DBusTopSortField>& f)
- {
- num_messages_ = 0;
- num_mc_ = 0;
- num_mr_ = 0;
- num_sig_ = 0;
- num_error_ = 0;
- stats_.clear();
- fields_ = f;
- }
-
- void Assign(DBusTopStatistics* out)
- {
- out->num_messages_ = this->num_messages_;
- out->num_mc_ = this->num_mc_;
- out->num_mr_ = this->num_mr_;
- out->num_sig_ = this->num_sig_;
- out->num_error_ = this->num_error_;
- out->seconds_since_last_sample_ = this->seconds_since_last_sample_;
- out->fields_ = this->fields_;
- out->stats_ = this->stats_;
- }
-
- void OnNewDBusMessage(const char* sender, const char* destination,
- const char* interface, const char* path,
- const char* message, const char type,
- sd_bus_message* m);
- std::string CheckAndFixNullString(const char* x)
- {
- if (x == nullptr)
- return "(null)";
- else
- return std::string(x);
- }
-
- std::map<std::vector<std::string>, DBusTopComputedMetrics> StatsSnapshot()
- {
- std::map<std::vector<std::string>, DBusTopComputedMetrics> ret;
- ret = stats_;
- return ret;
- }
-
- private:
- std::mutex mtx_;
-};
-
-int GetSummaryIntervalInMillises();
-// Monitor sensor details-related DBus method calls/replies
-// typedef void (*SetDBusTopConnection)(const char* conn);
-namespace dbus_top_analyzer
-{
- void Process();
- void Finish();
- typedef void (*DBusTopStatisticsCallback)(DBusTopStatistics*,
- Histogram<float>*);
- void SetDBusTopStatisticsCallback(DBusTopStatisticsCallback cb);
- void AnalyzerThread();
- // Methods for sending Object Mapper queries
- void ListAllSensors();
-} // namespace dbus_top_analyzer
diff --git a/dbus-top/bargraph.hpp b/dbus-top/bargraph.hpp
deleted file mode 100644
index 36f34a1..0000000
--- a/dbus-top/bargraph.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <stdio.h>
-
-#include <vector>
-
-template <typename ValueType>
-class BarGraph
-{
- public:
- std::vector<ValueType> history_; // is actually a ring buffer.
- int next_; // index to the slot where the next insertion will go
- int length_; // total # of data points that have ever been added
- explicit BarGraph(int capacity) : next_(0), length_(0)
- {
- history_.resize(capacity);
- std::fill(history_.begin(), history_.end(), 0);
- }
-
- // The last value is in [0], so on and so forth
- // Note: if there are not enough data, this function will return as much
- // as is available
- std::vector<float> GetLastNValues(int x)
- {
- std::vector<float> ret;
- const int N = static_cast<int>(history_.size());
- int imax = x;
- imax = std::min(imax, length_);
- imax = std::min(imax, N);
- int idx = (next_ - 1 + N) % N;
- for (int i = 0; i < imax; i++)
- {
- ret.push_back(history_[idx]);
- idx = (idx - 1 + N) % N;
- }
- return ret;
- }
-
- void AddValue(ValueType x)
- {
- history_[next_] = x;
- next_ = (next_ + 1) % history_.size();
- length_++;
- }
-};
diff --git a/dbus-top/dbus_capture.cpp b/dbus-top/dbus_capture.cpp
deleted file mode 100644
index 715fd41..0000000
--- a/dbus-top/dbus_capture.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "analyzer.hpp"
-#include "histogram.hpp"
-#include "sensorhelper.hpp"
-#include "main.hpp"
-
-#include <ncurses.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-
-#include <unordered_map>
-
-bool IS_USER_BUS = false; // User bus or System bus?
-extern sd_bus* g_bus;
-extern DBusConnectionSnapshot* g_connection_snapshot;
-static std::unordered_map<uint64_t, uint64_t> in_flight_methodcalls;
-
-namespace dbus_top_analyzer
-{
- extern DBusTopStatistics g_dbus_statistics;
- extern Histogram<float> g_mc_time_histogram;
-} // namespace dbus_top_analyzer
-
-static void TrackMessage(sd_bus_message* m)
-{}
-// Obtain a Monitoring DBus connection
-int AcquireBus(sd_bus** ret)
-{
- int r;
- r = sd_bus_new(ret);
- if (r < 0)
- {
- printf("Could not allocate bus: %s\n", strerror(-r));
- return 0;
- }
- r = sd_bus_set_monitor(*ret, true);
- if (r < 0)
- {
- printf("Could not set monitor mode: %s\n", strerror(-r));
- return 0;
- }
- r = sd_bus_negotiate_creds(*ret, true, _SD_BUS_CREDS_ALL);
- if (r < 0)
- {
- printf("Could not enable credentials: %s\n", strerror(-r));
- return 0;
- }
- r = sd_bus_negotiate_timestamp(*ret, true);
- if (r < 0)
- {
- printf("Could not enable timestamps: %s\n", strerror(-r));
- return 0;
- }
- r = sd_bus_negotiate_fds(*ret, true);
- if (r < 0)
- {
- printf("Could not enable fds: %s\n", strerror(-r));
- return 0;
- }
- r = sd_bus_set_bus_client(*ret, true);
- if (r < 0)
- {
- printf("Could not enable bus client: %s\n", strerror(-r));
- return 0;
- }
- if (IS_USER_BUS)
- {
- r = sd_bus_set_address(*ret, "haha");
- if (r < 0)
- {
- printf("Could not set user bus: %s\n", strerror(-r));
- return 0;
- }
- }
- else
- {
- r = sd_bus_set_address(*ret, "unix:path=/run/dbus/system_bus_socket");
- if (r < 0)
- {
- printf("Could not set system bus: %s\n", strerror(-r));
- return 0;
- }
- }
- r = sd_bus_start(*ret);
- if (r < 0)
- {
- printf("Could not connect to bus: %s\n", strerror(-r));
- return 0;
- }
- return r;
-}
-
-void DbusCaptureThread()
-{
- int r;
- // Become Monitor
- uint32_t flags = 0;
- sd_bus_message* message;
- sd_bus_error error = SD_BUS_ERROR_NULL;
- r = sd_bus_message_new_method_call(
- g_bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus",
- "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
- if (r < 0)
- {
- printf("Could not create the BecomeMonitor function call\n");
- exit(0);
- }
- // Match conditions
- r = sd_bus_message_open_container(message, 'a', "s");
- if (r < 0)
- {
- printf("Could not open container\n");
- exit(0);
- }
- r = sd_bus_message_close_container(message);
- if (r < 0)
- {
- printf("Could not close container\n");
- exit(0);
- }
- r = sd_bus_message_append_basic(message, 'u', &flags);
- if (r < 0)
- {
- printf("Could not append flags\n");
- exit(0);
- }
- r = sd_bus_call(g_bus, message, 0, &error, nullptr);
- if (r < 0)
- {
- printf("Could not call org.freedesktop.DBus.Monitoring.BecomeMonitor "
- "%d, %s\n",
- r, strerror(-r));
- exit(0);
- }
- const char* unique_name;
- r = sd_bus_get_unique_name(g_bus, &unique_name);
- if (r < 0)
- {
- printf("Could not get unique name: %s\n", strerror(-r));
- exit(0);
- }
- // Enter packet processing loop
- while (true)
- {
- struct sd_bus_message* m = nullptr;
- r = sd_bus_process(g_bus, &m);
- if (m != nullptr)
- {
- if (r < 0)
- {
- printf("Failed to call sd_bus_process: %s\n", strerror(-r));
- }
- uint8_t type;
- r = sd_bus_message_get_type(m, &type);
- const char* path = sd_bus_message_get_path(m);
- // const char* iface = sd_bus_message_get_interface(m);
- const char* sender = sd_bus_message_get_sender(m);
- const char* destination = sd_bus_message_get_destination(m);
- const char* interface = sd_bus_message_get_interface(m);
- const char* member = sd_bus_message_get_member(m);
- // TODO: This is for the bottom-left window
- TrackMessage(m);
-
- // Look up the unique connection name for sender and destination
- std::string sender_uniq, dest_uniq;
- if (sender != nullptr)
- {
- sender_uniq =
- g_connection_snapshot->GetUniqueNameIfExists(sender);
- }
- if (destination != nullptr)
- {
- dest_uniq =
- g_connection_snapshot->GetUniqueNameIfExists(destination);
- }
- // This is for the bottom-right window
- dbus_top_analyzer::g_dbus_statistics.OnNewDBusMessage(
- sender_uniq.c_str(), dest_uniq.c_str(), interface, path, member,
- type, m);
- sd_bus_message_unref(m);
- }
- r = sd_bus_wait(g_bus,
- (uint64_t)(GetSummaryIntervalInMillises() * 1000));
- if (r < 0)
- {
- printf("Failed to wait on bus: %s\n", strerror(-r));
- abort();
- }
- // Perform one analysis step
- dbus_top_analyzer::Process();
- }
-}
\ No newline at end of file
diff --git a/dbus-top/dbus_capture.hpp b/dbus-top/dbus_capture.hpp
deleted file mode 100644
index 825a519..0000000
--- a/dbus-top/dbus_capture.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <systemd/sd-bus.h>
-
-int AcquireBus(sd_bus** ret);
-void DbusCaptureThread();
diff --git a/dbus-top/dbus_top_recipe.bb b/dbus-top/dbus_top_recipe.bb
deleted file mode 100644
index 4de4f0e..0000000
--- a/dbus-top/dbus_top_recipe.bb
+++ /dev/null
@@ -1,23 +0,0 @@
-HOMEPAGE = "http://github.com/openbmc/openbmc-tools"
-PR = "r1"
-PV = "1.0+git${SRCPV}"
-
-LICENSE = "Apache-2.0"
-LIC_FILES_CHKSUM = "file://../LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
-
-SRC_URI += "git://github.com/openbmc-tools"
-SRCREV = "4a0e2e3c10327dac1c923d263929be9a20478b24"
-
-S = "${WORKDIR}/git/"
-inherit meson
-
-SUMMARY = "DBus-Top"
-DESCRIPTION = "DBUs-Top."
-GOOGLE_MISC_PROJ = "dbus-top"
-
-DEPENDS += "systemd"
-DEPENDS += "sdbusplus"
-DEPENDS += "phosphor-mapper"
-DEPENDS += "ncurses"
-
-inherit systemd
diff --git a/dbus-top/histogram.hpp b/dbus-top/histogram.hpp
deleted file mode 100644
index 750a9f4..0000000
--- a/dbus-top/histogram.hpp
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-#include <math.h>
-#include <stdio.h>
-
-#include <vector>
-template <typename ValueType>
-class Histogram
-{
- public:
- Histogram()
- {
- num_entries_ = 0;
- num_low_outliers_ = 0;
- num_high_outliers_ = 0;
- low_percentile_ = 0;
- high_percentile_ = 0;
- SetWindowSize(10000);
- SetCumulativeDensityThresholds(0.01f, 0.99f);
- }
-
- void AddSample(ValueType s)
- {
- int N = static_cast<int>(samples_.size());
- samples_[num_entries_ % N] = s;
- num_entries_++;
- }
-
- void SetBucketCount(int bc)
- {
- buckets_.resize(bc);
- }
-
- void SetWindowSize(int s)
- {
- samples_.resize(s);
- }
-
- void SetCumulativeDensityThresholds(float low_cd, float high_cd)
- {
- low_cum_density_ = low_cd;
- high_cum_density_ = high_cd;
- }
-
- void ComputeHistogram()
- {
- const int NS = static_cast<int>(samples_.size());
- int N = NS;
- if (num_entries_ < N)
- {
- N = num_entries_;
- }
- if (N <= 0)
- {
- return;
- }
- std::vector<ValueType> sorted;
- if (N == NS)
- sorted = samples_;
- else
- sorted.insert(sorted.end(), samples_.begin(), samples_.begin() + N);
- sort(sorted.begin(), sorted.end());
- int idx_low = static_cast<int>(N * low_cum_density_);
- int idx_high = static_cast<int>(N * high_cum_density_);
- if (idx_high - idx_low + 1 < 1)
- {
- return; // No entries can be shown, quit
- }
- max_bucket_height_ = 0;
- ValueType value_low = sorted[idx_low];
- ValueType value_high = sorted[idx_high];
- low_percentile_ = value_low;
- high_percentile_ = value_high;
- const int NB = static_cast<int>(buckets_.size()); // Number of Bins
- float bucket_width = (value_high - value_low) / NB;
- // If all values are the same, manually extend the range to
- // (value-1, value+1)
- const float EPS = 1e-4;
- if (fabs(value_high - value_low) <= EPS)
- {
- value_low = value_low - 1;
- value_high = value_high + 1;
- bucket_width = (value_high - value_low) / NB;
- }
- else
- {}
- buckets_.assign(NB, 0);
- num_low_outliers_ = 0;
- num_high_outliers_ = 0;
- for (int i = idx_low; i <= idx_high; i++)
- {
- ValueType v = sorted[i];
- ValueType dist = (v - value_low);
- int bucket_idx = dist / bucket_width;
- if (bucket_idx < 0)
- {
- num_low_outliers_++;
- }
- else if (bucket_idx >= NB)
- {
- num_high_outliers_++;
- }
- else
- {
- buckets_[bucket_idx]++;
- max_bucket_height_ =
- std::max(max_bucket_height_, buckets_[bucket_idx]);
- }
- }
- }
-
- int BucketHeight(int idx)
- {
- if (idx < 0 || idx >= static_cast<int>(buckets_.size()))
- return 0;
- return buckets_[idx];
- }
-
- void Assign(Histogram<ValueType>* out)
- {
- out->num_entries_ = num_entries_;
- out->samples_ = samples_;
- out->num_low_outliers_ = num_low_outliers_;
- out->num_high_outliers_ = num_high_outliers_;
- out->buckets_ = buckets_;
- out->low_cum_density_ = low_cum_density_;
- out->high_cum_density_ = high_cum_density_;
- out->low_percentile_ = low_percentile_;
- out->high_percentile_ = high_percentile_;
- out->max_bucket_height_ = max_bucket_height_;
- }
-
- int MaxBucketHeight()
- {
- return max_bucket_height_;
- }
-
- ValueType LowPercentile()
- {
- return low_percentile_;
- }
-
- ValueType HighPercentile()
- {
- return high_percentile_;
- }
-
- float LowCumDensity()
- {
- return low_cum_density_;
- }
-
- float HighCumDensity()
- {
- return high_cum_density_;
- }
-
- bool Empty()
- {
- return num_entries_ == 0;
- }
-
- int num_entries_;
- std::vector<ValueType> samples_;
- int num_low_outliers_, num_high_outliers_;
- std::vector<int> buckets_;
- float low_cum_density_, high_cum_density_;
- // "1% percentile" means "1% of the samples are below this value"
- ValueType low_percentile_, high_percentile_;
- int max_bucket_height_;
-};
\ No newline at end of file
diff --git a/dbus-top/main.cpp b/dbus-top/main.cpp
deleted file mode 100644
index 5293f9b..0000000
--- a/dbus-top/main.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "main.hpp"
-
-#include "analyzer.hpp"
-#include "bargraph.hpp"
-#include "dbus_capture.hpp"
-#include "histogram.hpp"
-#include "menu.hpp"
-#include "sensorhelper.hpp"
-#include "views.hpp"
-
-#include <fmt/printf.h>
-#include <ncurses.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <iomanip>
-#include <sstream>
-#include <thread>
-
-DBusTopWindow* g_current_active_view;
-SummaryView* g_summary_window;
-SensorDetailView* g_sensor_detail_view;
-DBusStatListView* g_dbus_stat_list_view;
-FooterView* g_footer_view;
-BarGraph<float>* g_bargraph = nullptr;
-Histogram<float>* g_histogram;
-std::vector<DBusTopWindow*> g_views;
-int g_highlighted_view_index = INVALID;
-sd_bus* g_bus = nullptr;
-SensorSnapshot* g_sensor_snapshot;
-DBusConnectionSnapshot* g_connection_snapshot;
-DBusTopStatistics* g_dbus_statistics; // At every update interval,
- // dbus_top_analyzer::g_dbus_statistics's
- // value is copied to this one for display
-void ReinitializeUI();
-int maxx, maxy, halfx, halfy;
-
-void ActivateWindowA()
-{
- g_views[0]->visible_=true;
- g_views[0]->maximize_=true;
- g_views[1]->visible_=false;
- g_views[2]->visible_=false;
-}
-
-void ActivateWindowB()
-{
- g_views[1]->visible_=true;
- g_views[1]->maximize_=true;
- g_views[0]->visible_=false;
- g_views[2]->visible_=false;
-}
-void ActivateWindowC()
-{
- g_views[2]->visible_=true;
- g_views[2]->maximize_=true;
- g_views[0]->visible_=false;
- g_views[1]->visible_=false;
-}
-void ActivateAllWindows()
-{
- g_views[0]->maximize_ = false;
- g_views[1]->maximize_=false;
- g_views[2]->maximize_=false;
- g_views[0]->visible_=true;
- g_views[1]->visible_=true;
- g_views[2]->visible_= true;
-}
-
-void InitColorPairs()
-{
- init_pair(1, COLOR_WHITE, COLOR_BLACK); // Does not work on actual machine
- init_pair(2, COLOR_BLACK, COLOR_WHITE);
-}
-
-// Returns number of lines drawn
-int DrawTextWithWidthLimit(WINDOW* win, std::string txt, int y, int x,
- int width, const std::string& delimiters)
-{
- int ret = 0;
- std::string curr_word, curr_line;
- while (txt.empty() == false)
- {
- ret++;
- if (static_cast<int>(txt.size()) > width)
- {
- mvwaddstr(win, y, x, txt.substr(0, width).c_str());
- txt = txt.substr(width);
- }
- else
- {
- mvwaddstr(win, y, x, txt.c_str());
- break;
- }
- y++;
- }
- return ret;
-}
-
-void UpdateWindowSizes()
-{
- /* calculate window sizes and locations */
- if (getenv("FIXED_TERMINAL_SIZE"))
- {
- maxx = 100;
- maxy = 30;
- }
- else
- {
- getmaxyx(stdscr, maxy, maxx);
- halfx = maxx >> 1;
- halfy = maxy >> 1;
- }
- for (DBusTopWindow* v : g_views)
- {
- v->OnResize(maxx, maxy);
- if(v->maximize_){
- v->rect={0,0,maxx,maxy-MARGIN_BOTTOM};
- v->UpdateWindowSizeAndPosition();
- }
- }
-}
-
-std::string FloatToString(float value)
-{
- return fmt::sprintf("%.2f", value);
-}
-
-void DBusTopRefresh()
-{
- UpdateWindowSizes();
- for (DBusTopWindow* v : g_views)
- {
- v->Render();
- }
- DBusTopWindow* focused_view = g_current_active_view;
- if (focused_view)
- {
- focused_view->DrawBorderIfNeeded(); // focused view border: on top
- }
- refresh();
-}
-
-// This function is called by the Capture thread
-void DBusTopStatisticsCallback(DBusTopStatistics* stat, Histogram<float>* hist)
-{
- if (stat == nullptr)
- return;
- // Makes a copy for display
- // TODO: Add a mutex here for safety
- stat->Assign(g_dbus_statistics);
- hist->Assign(g_histogram);
- float interval_secs = stat->seconds_since_last_sample_;
- if (interval_secs == 0)
- {
- interval_secs = GetSummaryIntervalInMillises() / 1000.0f;
- }
- g_summary_window->UpdateDBusTopStatistics(stat);
- stat->SetSortFieldsAndReset(g_dbus_stat_list_view->GetSortFields());
- // ReinitializeUI(); // Don't do it here, only when user presses [R]
- DBusTopRefresh();
-}
-
-void CycleHighlightedView()
-{
- int new_index = 0;
- if (g_highlighted_view_index == INVALID)
- {
- new_index = 0;
- }
- else
- {
- new_index = g_highlighted_view_index + 1;
- }
- while (new_index < static_cast<int>(g_views.size()) &&
- g_views[new_index]->selectable_ == false)
- {
- new_index++;
- }
- if (new_index >= static_cast<int>(g_views.size()))
- {
- new_index = INVALID;
- }
- // Un-highlight all
- for (DBusTopWindow* v : g_views)
- {
- v->focused_ = false;
- }
- if (new_index != INVALID)
- {
- g_views[new_index]->focused_ = true;
- g_current_active_view = g_views[new_index];
- }
- else
- {
- g_current_active_view = nullptr;
- }
- g_highlighted_view_index = new_index;
- DBusTopRefresh();
-}
-
-int UserInputThread()
-{
- while (true)
- {
- int c = getch();
- DBusTopWindow* curr_view = g_current_active_view;
- // If a view is currently focused on
- if (curr_view)
- {
- switch (c)
- {
- case '\e': // 27 in dec, 0x1B in hex, escape key
- {
- getch();
- c = getch();
- switch (c)
- {
- case 'A':
- curr_view->OnKeyDown("up");
- break;
- case 'B':
- curr_view->OnKeyDown("down");
- break;
- case 'C':
- curr_view->OnKeyDown("right");
- break;
- case 'D':
- curr_view->OnKeyDown("left");
- break;
- case '\e':
- curr_view->OnKeyDown("escape");
- break;
- }
- break;
- }
- case '\n': // 10 in dec, 0x0A in hex, line feed
- {
- curr_view->OnKeyDown("enter");
- break;
- }
- case 'q':
- case 'Q': // Q key
- {
- curr_view->OnKeyDown("escape");
- break;
- }
- case 'a':
- case 'A': // A key
- {
- curr_view->OnKeyDown("a");
- break;
- }
- case 'd':
- case 'D': // D key
- {
- curr_view->OnKeyDown("d");
- break;
- }
- case 33: // Page up
- {
- curr_view->OnKeyDown("pageup");
- break;
- }
- case 34: // Page down
- {
- curr_view->OnKeyDown("pagedown");
- break;
- }
- case ' ': // Spacebar
- {
- curr_view->OnKeyDown("space");
- break;
- }
- }
- }
- // The following keys are registered both when a view is selected and
- // when it is not
- switch (c)
- {
- case '\t': // 9 in dec, 0x09 in hex, tab
- {
- CycleHighlightedView();
- break;
- }
- case 'r':
- case 'R':
- {
- ReinitializeUI();
- DBusTopRefresh();
- break;
- }
- case 'x':
- case 'X':
- {
- clear();
- ActivateWindowA();
- break;
- }
- case 'y':
- case 'Y':
- {
- clear();
- ActivateWindowB();
- break;
- }
- case 'z':
- case 'Z':
- {
- clear();
- ActivateWindowC();
- break;
- }
- case 'h':
- case 'H':
- {
- ActivateAllWindows();
- DBusTopRefresh();
- }
- default:
- break;
- }
- }
- exit(0);
-}
-
-void ReinitializeUI()
-{
- endwin();
- initscr();
- use_default_colors();
- noecho();
- for (int i = 0; i < static_cast<int>(g_views.size()); i++)
- {
- g_views[i]->RecreateWindow();
- }
-}
-
-int main(int argc, char** argv)
-{
- int r = AcquireBus(&g_bus);
- if (r <= 0)
- {
- printf("Error acquiring bus for monitoring\n");
- exit(0);
- }
-
- printf("Listing all sensors for display\n");
- // ListAllSensors creates connection snapshot and sensor snapshot
- dbus_top_analyzer::ListAllSensors();
- g_bargraph = new BarGraph<float>(300);
- g_histogram = new Histogram<float>();
-
- initscr();
- use_default_colors();
- start_color();
- noecho();
-
- clear();
- g_dbus_statistics = new DBusTopStatistics();
- g_summary_window = new SummaryView();
- g_sensor_detail_view = new SensorDetailView();
- g_dbus_stat_list_view = new DBusStatListView();
- g_footer_view = new FooterView();
- g_views.push_back(g_summary_window);
- g_views.push_back(g_sensor_detail_view);
- g_views.push_back(g_dbus_stat_list_view);
- g_views.push_back(g_footer_view);
-
- g_sensor_detail_view->UpdateSensorSnapshot(g_sensor_snapshot);
- UpdateWindowSizes();
- dbus_top_analyzer::SetDBusTopStatisticsCallback(&DBusTopStatisticsCallback);
- std::thread capture_thread(DbusCaptureThread);
- std::thread user_input_thread(UserInputThread);
- capture_thread.join();
-
- return 0;
-}
diff --git a/dbus-top/main.hpp b/dbus-top/main.hpp
deleted file mode 100644
index 91c07da..0000000
--- a/dbus-top/main.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "bargraph.hpp"
-
-#include <ncurses.h>
-
-#include <string>
-
-const int INVALID = -999; // Constant indicating invalid indices
-struct Rect
-{
- int x, y, w, h; // X, Y, Width, Height
- Rect(int _x, int _y, int _w, int _h) : x(_x), y(_y), w(_w), h(_h)
- {}
- Rect() : x(0), y(0), w(1), h(1)
- {}
-};
-
-int DrawTextWithWidthLimit(WINDOW* win, std::string txt, int y, int x,
- int width, const std::string& delimiters);
-std::string FloatToString(float value);
-template <typename T>
-void HistoryBarGraph(WINDOW* win, const Rect& rect, BarGraph<T>* bargraph);
diff --git a/dbus-top/menu.cpp b/dbus-top/menu.cpp
deleted file mode 100644
index 47d1f57..0000000
--- a/dbus-top/menu.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "menu.hpp"
-
-#include "views.hpp"
-
-ArrowKeyNavigationMenu::ArrowKeyNavigationMenu(DBusTopWindow* view) :
- win_(view->win), parent_(view), idx0_(INVALID), idx1_(INVALID),
- h_padding_(2), col_width_(15), h_spacing_(2), choice_(INVALID)
-{}
-
-void ArrowKeyNavigationMenu::do_Render(bool is_column_major)
-{
- const int nrows = DispEntriesPerColumn();
- const int ncols = DispEntriesPerRow();
- const int items_per_page = nrows * ncols;
- if (items_per_page < 1)
- return;
- int tot_num_items = items_.size();
- // int tot_num_columns = (tot_num_items - 1) / nrows + 1;
- // Determine whether cursor is outside the current rectangular viewport
- bool is_cursor_out_of_view = false;
- if (idx0_ > choice_ || idx1_ <= choice_)
- {
- is_cursor_out_of_view = true;
- }
- if (idx0_ == INVALID || idx1_ == INVALID)
- {
- is_cursor_out_of_view = true;
- }
- // Scroll the viewport such that it contains the cursor
- if (is_cursor_out_of_view)
- {
- idx0_ = 0;
- idx1_ = items_per_page;
- }
- while (idx1_ <= choice_)
- {
- if (is_column_major)
- {
- idx0_ += nrows;
- idx1_ += nrows;
- }
- else
- {
- idx0_ += ncols;
- idx1_ += ncols;
- }
- }
- int y0 = rect_.y, x0 = rect_.x;
- int y = y0, x = x0;
- for (int i = 0; i < items_per_page; i++)
- {
- int idx = idx0_ + i;
- if (idx < tot_num_items)
- {
- if (idx == choice_)
- {
- wattrset(win_, A_REVERSE);
- }
- std::string s = items_[idx];
- while (s.size() < col_width_)
- {
- s.push_back(' ');
- }
- mvwaddstr(win_, y, x, s.c_str());
- wattrset(win_, 0);
- }
- else
- {
- break;
- }
- if (is_column_major)
- {
- y++;
- if (i % nrows == nrows - 1)
- {
- y = y0;
- x += col_width_ + h_spacing_;
- }
- }
- else
- {
- x += col_width_ + h_spacing_;
- if (i % ncols == ncols - 1)
- {
- x = x0;
- y++;
- }
- }
- }
-}
-
-void ArrowKeyNavigationMenu::Render()
-{
- do_Render(order == ColumnMajor);
-}
-
-void ArrowKeyNavigationMenu::OnKeyDown(const std::string& key)
-{
- switch (order)
- {
- case ColumnMajor:
- if (key == "up")
- {
- MoveCursorAlongPrimaryAxis(-1);
- }
- else if (key == "down")
- {
- MoveCursorAlongPrimaryAxis(1);
- }
- else if (key == "left")
- {
- MoveCursorAlongSecondaryAxis(-1);
- }
- else if (key == "right")
- {
- MoveCursorAlongSecondaryAxis(1);
- }
- break;
- case RowMajor:
- if (key == "up")
- {
- MoveCursorAlongSecondaryAxis(-1);
- }
- else if (key == "down")
- {
- MoveCursorAlongSecondaryAxis(1);
- }
- else if (key == "left")
- {
- MoveCursorAlongPrimaryAxis(-1);
- }
- else if (key == "right")
- {
- MoveCursorAlongPrimaryAxis(1);
- }
- break;
- break;
- }
-}
-
-void ArrowKeyNavigationMenu::MoveCursorAlongPrimaryAxis(int delta)
-{
- const int N = items_.size();
- if (N < 1)
- return;
- // If the cursor is inactive, activate it
- if (choice_ == INVALID)
- {
- if (delta > 0)
- {
- choice_ = 0;
- }
- else
- {
- choice_ = N - 1;
- }
- return;
- }
- int choice_next = choice_ + delta;
- while (choice_next >= N)
- {
- choice_next -= N;
- }
- while (choice_next < 0)
- {
- choice_next += N;
- }
- choice_ = choice_next;
-}
-
-void ArrowKeyNavigationMenu::MoveCursorAlongSecondaryAxis(int delta)
-{
- if (delta != 0 && delta != 1 && delta != -1)
- return;
- const int N = items_.size();
- if (N < 1)
- return;
- // If the cursor is inactive, activate it
- if (choice_ == INVALID)
- {
- if (delta > 0)
- {
- choice_ = 0;
- }
- else
- {
- choice_ = N - 1;
- }
- return;
- }
- const int nrows =
- (order == ColumnMajor) ? DispEntriesPerColumn() : DispEntriesPerRow();
- const int tot_columns = (N - 1) / nrows + 1;
- const int num_rows_last_column = N - nrows * (tot_columns - 1);
- int y = choice_ % nrows, x = choice_ / nrows;
- if (delta == 1)
- {
- x++;
- }
- else
- {
- x--;
- }
- bool overflow_to_right = false;
- if (y < num_rows_last_column && x >= tot_columns)
- {
- overflow_to_right = true;
- }
- if (y >= num_rows_last_column && x >= tot_columns - 1)
- {
- overflow_to_right = true;
- }
- bool overflow_to_left = false;
- if (x < 0)
- {
- overflow_to_left = true;
- }
- if (overflow_to_right)
- {
- y++;
- if (y >= nrows)
- {
- choice_ = 0;
- return;
- }
- else
- {
- choice_ = y;
- return;
- }
- }
- else if (overflow_to_left)
- {
- y--;
- if (y < 0)
- {
- if (num_rows_last_column == nrows)
- {
- choice_ = N - 1;
- }
- else
- {
- choice_ = N - num_rows_last_column - 1;
- }
- return;
- }
- else
- {
- if (y < num_rows_last_column)
- {
- choice_ = nrows * (tot_columns - 1) + y;
- }
- else
- {
- choice_ = nrows * (tot_columns - 2) + y;
- }
- }
- }
- else
- {
- choice_ = y + x * nrows;
- }
-}
-
-void ArrowKeyNavigationMenu::SetChoiceAndConstrain(int c)
-{
- if (Empty())
- {
- choice_ = INVALID;
- return;
- }
- if (c < 0)
- c = 0;
- if (c >= static_cast<int>(items_.size()))
- {
- c = static_cast<int>(items_.size() - 1);
- }
- choice_ = c;
-}
-
-void ArrowKeyNavigationMenu::AddItem(const std::string& s)
-{
- items_.push_back(s);
-}
-
-bool ArrowKeyNavigationMenu::RemoveHighlightedItem(std::string* ret)
-{
- if (choice_ < 0 || choice_ >= items_.size())
- return false;
- std::string r = items_[choice_];
- items_.erase(items_.begin() + choice_);
- if (items_.empty())
- {
- Deselect();
- }
- else
- {
- if (choice_ >= items_.size())
- {
- choice_ = items_.size() - 1;
- }
- }
- if (ret)
- {
- *ret = r;
- }
- return true;
-}
diff --git a/dbus-top/menu.hpp b/dbus-top/menu.hpp
deleted file mode 100644
index afb4110..0000000
--- a/dbus-top/menu.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-#include "main.hpp"
-
-#include <ncurses.h>
-
-#include <string>
-#include <vector>
-class DBusTopWindow;
-class ArrowKeyNavigationMenu
-{
- public:
- explicit ArrowKeyNavigationMenu(WINDOW* win) :
- win_(win), h_padding_(2), col_width_(15), h_spacing_(2), idx0_(INVALID),
- idx1_(INVALID), choice_(INVALID), parent_(nullptr)
- {}
- explicit ArrowKeyNavigationMenu(DBusTopWindow* view);
- void LoadDummyValues()
- {
- items_.clear();
- items_.push_back("Sender");
- items_.push_back("Destination");
- items_.push_back("Interface");
- items_.push_back("Path");
- items_.push_back("Member");
- }
-
- void OnKeyDown(const std::string& key);
- void Render();
- void MoveCursorAlongSecondaryAxis(int delta);
- void MoveCursorAlongPrimaryAxis(int delta);
- int DispEntriesPerRow()
- {
- int ncols = 0;
- while (true)
- {
- int next = ncols + 1;
- int w = 2 * h_padding_ + col_width_ * next;
- if (next > 1)
- w += (next - 1) * h_spacing_;
- if (w <= rect_.w - 2)
- {
- ncols = next;
- }
- else
- {
- break;
- }
- }
- return ncols;
- }
-
- int DispEntriesPerColumn()
- {
- return rect_.h;
- }
-
- void SetRect(const Rect& rect)
- {
- rect_ = rect;
- }
-
- enum Order
- {
- ColumnMajor,
- RowMajor,
- };
-
- void SetOrder(Order o)
- {
- order = o;
- }
-
- int Choice()
- {
- return choice_;
- }
-
- void Deselect()
- {
- choice_ = INVALID;
- }
-
- bool Empty()
- {
- return items_.empty();
- }
-
- void SetChoiceAndConstrain(int c);
- Rect rect_;
- void AddItem(const std::string& s);
- bool RemoveHighlightedItem(std::string* ret); // returns true if successful
- std::vector<std::string> Items()
- {
- return items_;
- }
-
- void do_Render(bool is_column_major);
- std::vector<std::string> items_;
- WINDOW* win_;
- int h_padding_;
- int col_width_;
- int h_spacing_;
- int idx0_, idx1_;
- int choice_;
- DBusTopWindow* parent_;
- Order order;
-};
-
diff --git a/dbus-top/meson.build b/dbus-top/meson.build
deleted file mode 100644
index 60d4641..0000000
--- a/dbus-top/meson.build
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-project('dbus-top', 'cpp',
- version: '0.1',
- default_options:
- [
- 'cpp_std=c++17',
- ],
-)
-
-cmake = import('cmake')
-fmt_proj = cmake.subproject('fmt')
-fmt_dep = fmt_proj.dependency('fmt')
-
-bindir = get_option('prefix') / get_option('bindir')
-executable('dbus-top',
- [
- 'menu.cpp',
- 'analyzer.cpp',
- 'dbus_capture.cpp',
- 'sensorhelper.cpp',
- 'xmlparse.cpp',
- 'views.cpp',
- 'main.cpp',
- ],
- dependencies:
- [
- dependency('systemd'),
- dependency('sdbusplus'),
- dependency('ncurses'),
- dependency('threads'),
- fmt_dep
- ],
- install: true,
- install_dir: bindir
-)
diff --git a/dbus-top/rect.hpp b/dbus-top/rect.hpp
deleted file mode 100644
index aa7bf89..0000000
--- a/dbus-top/rect.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-struct Rect
-{
- int x, y, w, h; // X, Y, Width, Height
- Rect(int _x, int _y, int _w, int _h) : x(_x), y(_y), w(_w), h(_h)
- {}
- Rect() : x(0), y(0), w(1), h(1)
- {}
-};
\ No newline at end of file
diff --git a/dbus-top/sensorhelper.cpp b/dbus-top/sensorhelper.cpp
deleted file mode 100644
index 3f8bba6..0000000
--- a/dbus-top/sensorhelper.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "sensorhelper.hpp"
-#include "main.hpp"
-
-#include <unistd.h>
-
-#include <cassert>
-#include <fstream>
-#include <functional>
-#include <sstream>
-#include <string>
-#include <vector>
-
-extern SensorSnapshot* g_sensor_snapshot;
-extern DBusConnectionSnapshot* g_connection_snapshot;
-
-std::vector<std::string> MySplit(const std::string& s)
-{
- int idx = 0, prev_idx = 0;
- std::vector<std::string> ret;
- while (idx <= static_cast<int>(s.size()))
- {
- if (idx == static_cast<int>(s.size()) || s[idx] == '/')
- {
- if (idx > prev_idx)
- {
- ret.push_back(s.substr(prev_idx, idx - prev_idx));
- }
- prev_idx = idx + 1;
- }
- idx++;
- }
- return ret;
-}
-
-// Example: /xyz/openbmc_project/sensors/temperature/powerseq_temp
-bool IsSensorObjectPath(const std::string& s)
-{
- std::vector<std::string> sections = MySplit(s);
- if (sections.size() == 5 && sections[0] == "xyz" &&
- sections[1] == "openbmc_project" && sections[2] == "sensors")
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-// Example: /xyz/openbmc_project/sensors/temperature/powerseq_temp/chassis
-bool IsSensorObjectPathWithAssociation(const std::string& s,
- std::string* sensor_obj_path)
-{
- std::vector<std::string> sections = MySplit(s);
- if (sections.size() == 6)
- {
- size_t idx = s.rfind('/');
- return IsSensorObjectPath(s.substr(0, idx));
- }
- else
- {
- return false;
- }
-}
-
-bool IsUniqueName(const std::string& x)
-{
- if (x.empty())
- return false;
- if (x[0] != ':')
- return false;
- if (x[0] == ':')
- {
- for (int i = 1; i < int(x.size()); i++)
- {
- const char ch = x[i];
- if (ch >= '0' || ch <= '9')
- continue;
- else if (ch == '.')
- continue;
- else
- return false;
- }
- }
- return true;
-}
-
-std::vector<std::string> FindAllObjectPathsForService(
- const std::string& service,
- std::function<void(const std::string&, const std::vector<std::string>&)>
- on_interface_cb)
-{
- // Not available for PCAP replay, only valid with actual DBus capture
- assert(false);
-}
-
-bool IsWhitespace(const char c)
-{
- if (c == ' ' || c == '\r' || c == '\n')
- return true;
- else
- return false;
-}
-
-std::string Trim(const std::string& s)
-{
- const int N = int(s.size());
- int idx0 = 0, idx1 = int(N - 1);
- while (idx0 < N && IsWhitespace(s[idx0]))
- idx0++;
- while (idx1 >= 0 && IsWhitespace(s[idx1]))
- idx1--;
- if (idx0 >= N || idx1 < 0)
- return "";
- return s.substr(idx0, idx1 - idx0 + 1);
-}
diff --git a/dbus-top/sensorhelper.hpp b/dbus-top/sensorhelper.hpp
deleted file mode 100644
index a619c4a..0000000
--- a/dbus-top/sensorhelper.hpp
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "main.hpp"
-// This is the form a sensor assumes on DBus.
-// Aggregates their view from all other daemons.
-#include <bitset>
-#include <optional>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-// Where is this sensor seen?
-constexpr int VISIBILITY_OBJECT_MAPPER = 0;
-constexpr int VISIBILITY_HWMON = 1;
-constexpr int VISIBILITY_IPMITOOL_SDR = 2;
-class DBusConnection
-{
- public:
- std::string service; // example: "systemd-resolved"
- std::string connection; // example: ":1.1"
- std::string cmd; // the comm line
- std::string unit; // example: "systemd-resolved.service"
- int pid;
- // For actual DBus capture: service name, connection name, command line,
- // systmed unit and PID are all known
- DBusConnection(const std::string& _s, const std::string& _c,
- const std::string& _cmd, const std::string& _u, int _pid)
- {
- service = _s;
- connection = _c;
- cmd = _cmd;
- unit = _u;
- pid = _pid;
- }
-
- // During PCap replay: only service name, connection name, and PID are known
- // cmd and unit are not known since they are not
- // stored in the PCap file
- DBusConnection(const std::string& _s, const std::string& _c, int _pid)
- {
- service = _s;
- connection = _c;
- pid = _pid;
- }
-};
-
-class DBusConnectionSnapshot
-{
- public:
- std::vector<DBusConnection*> connections_;
- std::unordered_map<std::string, DBusConnection*> unique_name_to_cxn;
- DBusConnection* FindDBusConnectionByService(const std::string& service)
- {
- for (DBusConnection* cxn : connections_)
- {
- if (cxn->service == service)
- return cxn;
- }
- return nullptr;
- }
-
- void SetConnectionPID(const std::string& connection, int pid)
- {
- DBusConnection* cxn = FindDBusConnectionByService(connection);
- if (cxn != nullptr)
- {
- cxn->pid = pid;
- unique_name_to_cxn[connection] = cxn; // Just to make sure
- }
- }
-
- void SetConnectionUniqueName(const std::string& service,
- const std::string& unique_name)
- {
- DBusConnection* cxn = FindDBusConnectionByService(service);
- if (cxn != nullptr)
- {
- cxn->connection = unique_name;
- unique_name_to_cxn[unique_name] = cxn;
- }
- }
-
- DBusConnection* FindDBusConnectionByConnection(const std::string& conn)
- {
- for (DBusConnection* cxn : connections_)
- {
- if (cxn->connection == conn)
- return cxn;
- }
- return nullptr;
- }
-
-
- // Only when service is known (during playback)
- void AddConnection(const std::string& _s)
- {
- connections_.push_back(new DBusConnection(_s, "", "", "", INVALID));
- }
-
- // When all 5 pieces of details are known (during actual capture)
- void AddConnection(const std::string& _s, const std::string& _connection,
- const std::string& _cmd, const std::string& _unit,
- int _pid)
- {
- DBusConnection* cxn =
- new DBusConnection(_s, _connection, _cmd, _unit, _pid);
- connections_.push_back(cxn);
- unique_name_to_cxn[_connection] = cxn;
- }
-
- int GetConnectionPIDFromNameOrUniqueName(const std::string& key)
- {
- if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
- {
- return INVALID;
- }
- else
- {
- return unique_name_to_cxn[key]->pid;
- }
- }
-
- std::string GetConnectionCMDFromNameOrUniqueName(const std::string& key)
- {
- if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
- {
- return "(unknown)";
- }
- else
- {
- return unique_name_to_cxn[key]->cmd;
- }
- }
-
- std::string GetUniqueNameIfExists(const std::string service)
- {
- for (DBusConnection* cxn : connections_)
- {
- if (cxn->service == service)
- return cxn->connection;
- }
- return service;
- }
-
-};
-
-// Each sensor might have different units, for example current and voltage
-class Sensor
-{
- public:
- DBusConnection* connection_;
- // Example: "/xyz/openbmc_project/sensors/temperature/powerseq_temp"
- std::string object_path_;
- std::string SensorID()
- {
- const size_t idx = object_path_.rfind('/');
- if (idx != std::string::npos)
- {
- return object_path_.substr(idx + 1);
- }
- else
- return ("unknown sensor");
- }
-
- std::string ServiceName()
- {
- if (connection_ == nullptr)
- return "";
- else
- return connection_->service;
- }
-
- std::string ConnectionName()
- {
- if (connection_ == nullptr)
- return "";
- else
- return connection_->connection;
- }
-
- std::string ObjectPath()
- {
- return object_path_;
- }
-
- // Should contain the following:
- // 1. "org.freedesktop.DBus.Introspectable"
- // 2. "org.freedesktop.DBus.Peer"
- // 3. "org.freedesktop.DBus.Properties"
- // 4. "xyz.openbmc_project.Sensor.Value"
- // 5. "xyz.openbmc_project.State.Decorator.OperationalStatus"
- std::set<std::string> interfaces_;
- std::bitset<4> visibility_flags_;
- std::set<std::string> associations_;
-};
-
-class SensorSnapshot
-{
- public:
- std::vector<std::string> GetDistinctSensorNames()
- {
- std::unordered_set<std::string> seen;
- std::vector<std::string> ret;
- for (Sensor* s : sensors_)
- {
- std::string sn = s->SensorID();
- if (seen.find(sn) == seen.end())
- {
- ret.push_back(sn);
- seen.insert(sn);
- }
- }
- return ret;
- }
-
- explicit SensorSnapshot(DBusConnectionSnapshot* cs)
- {
- connection_snapshot_ = cs;
- }
-
- ~SensorSnapshot()
- {
- for (Sensor* s : sensors_)
- {
- delete s;
- }
- }
-
- int SensorCount()
- {
- return int(sensors_.size());
- }
-
- Sensor* FindOrCreateSensorByServiceAndObject(const std::string& service,
- const std::string& object)
- {
- Sensor* ret = nullptr;
- for (Sensor* s : sensors_)
- {
- if (s->ServiceName() == service && s->object_path_ == object)
- {
- ret = s;
- break;
- }
- }
- if (ret == nullptr)
- {
- DBusConnection* cxn =
- connection_snapshot_->FindDBusConnectionByService(service);
- ret = new Sensor();
- ret->connection_ = cxn;
- ret->object_path_ = object;
- sensors_.push_back(ret);
- }
- return ret;
- }
-
- // Note: one sensor_id might correspond to multiple sensors.
- // Example: "VDD" can have all 3 of power, current and voltage.
- std::vector<Sensor*> FindSensorsBySensorID(const std::string& sensor_id)
- {
- std::vector<Sensor*> ret;
- for (Sensor* s : sensors_)
- {
- const std::string& p = s->object_path_;
- if (p.find(sensor_id) == p.size() - sensor_id.size())
- {
- ret.push_back(s);
- }
- }
- return ret;
- }
-
- // This sensor is visible from Object Mapper
- void SerSensorVisibleFromObjectMapper(const std::string& service,
- const std::string& object)
- {
- Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
- s->visibility_flags_.set(VISIBILITY_OBJECT_MAPPER);
- }
-
- // This sensor is visible from Hwmon
- void SetSensorVisibleFromHwmon(const std::string& service,
- const std::string& object)
- {
- Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
- s->visibility_flags_.set(VISIBILITY_HWMON);
- }
-
- // This sensor is visible from `ipmitool sdr`
- // The first column is referred to as "sensorid".
- void SetSensorVisibleFromIpmitoolSdr(const std::string& sensor_id)
- {
- std::vector<Sensor*> sensors = FindSensorsBySensorID(sensor_id);
- for (Sensor* s : sensors)
- s->visibility_flags_.set(VISIBILITY_IPMITOOL_SDR);
- }
-
- void PrintSummary()
- {
- for (Sensor* s : sensors_)
- {
- printf("%50s %50s %9s\n", s->ServiceName().c_str(),
- s->object_path_.c_str(),
- s->visibility_flags_.to_string().c_str());
- }
- }
-
- Sensor* FindSensorByDBusUniqueNameOrServiceName(const std::string& key)
- {
- for (Sensor* s : sensors_)
- {
- if (s->ConnectionName() == key || s->ServiceName() == key)
- return s;
- }
- return nullptr;
- }
-
- private:
- std::vector<Sensor*> sensors_;
- std::unordered_map<std::string, int> conn2pid_;
- DBusConnectionSnapshot* connection_snapshot_;
-};
-
-bool IsSensorObjectPath(const std::string& s);
-bool IsUniqueName(const std::string& x);
-std::string Trim(const std::string& s);
diff --git a/dbus-top/subprojects/fmt.wrap b/dbus-top/subprojects/fmt.wrap
deleted file mode 100644
index 6847ae5..0000000
--- a/dbus-top/subprojects/fmt.wrap
+++ /dev/null
@@ -1,3 +0,0 @@
-[wrap-git]
-url = https://github.com/fmtlib/fmt
-revision = HEAD
diff --git a/dbus-top/subprojects/sdbusplus.wrap b/dbus-top/subprojects/sdbusplus.wrap
deleted file mode 100644
index 7b076d0..0000000
--- a/dbus-top/subprojects/sdbusplus.wrap
+++ /dev/null
@@ -1,6 +0,0 @@
-[wrap-git]
-url = https://github.com/openbmc/sdbusplus.git
-revision = HEAD
-
-[provide]
-sdbusplus = sdbusplus_dep
diff --git a/dbus-top/views.cpp b/dbus-top/views.cpp
deleted file mode 100644
index fdbf85d..0000000
--- a/dbus-top/views.cpp
+++ /dev/null
@@ -1,1236 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "views.hpp"
-#include "bargraph.hpp"
-#include "histogram.hpp"
-#include "menu.hpp"
-#include <string.h>
-#include <algorithm>
-
-extern SensorSnapshot* g_sensor_snapshot;
-extern BarGraph<float>* g_bargraph;
-extern DBusTopStatistics* g_dbus_statistics;
-extern Histogram<float>* g_histogram;
-extern DBusTopWindow* g_current_active_view;
-extern const std::string FieldNames[];
-extern const int FieldPreferredWidths[];
-
-namespace dbus_top_analyzer
-{
- extern DBusTopStatistics g_dbus_statistics;
-}
-
-// Linear interpolation
-float Lerp(float a, float b, float t)
-{
- return a + t * (b - a);
-}
-
-// Linear map
-float Map(float value, float start1, float stop1, float start2, float stop2,
- bool within_bounds)
-{
- float t = (value - start1) / (stop1 - start1);
- float ret = Lerp(start2, stop2, t);
- if (within_bounds)
- {
- if (ret < start2)
- ret = start2;
- if (ret > stop2)
- ret = stop2;
- }
- return ret;
-}
-
-template <typename T>
-void HistoryBarGraph(WINDOW* win, const Rect& rect, BarGraph<T>* bargraph)
-{
- const int RIGHT_MARGIN = 5;
- const int x0 = rect.x, y0 = 2;
- const int w = rect.w - 2 - RIGHT_MARGIN;
- const int h = rect.h - 3; // height of content
- wattrset(win, 0);
- wattron(win, A_BOLD | A_UNDERLINE);
- mvwaddstr(win, 1, x0, "History (Total msg/s)");
- wattrset(win, 0);
- // 1. Obtain data, determine Y range
- std::vector<float> data = bargraph->GetLastNValues(w - RIGHT_MARGIN - 1);
- float ymax = -1e20, ymin = 1e20;
- if (data.empty())
- {
- data.push_back(0);
- ymin = 0;
- ymax = 10;
- }
- else
- {
- for (const float x : data)
- {
- ymax = std::max(ymax, x);
- ymin = std::min(ymin, x);
- }
- }
- // Fix edge case for both == 0
- float diff = ymax - ymin;
- if (diff < 0)
- {
- diff = -diff;
- }
- const float EPS = 1e-4;
- if (diff < EPS)
- {
- ymax += 10;
- ymin -= 10;
- }
- // Choose a suitable round-up unit to snap the grid labels to
- int snap = 1;
- if (ymax < 100)
- {
- snap = 10;
- }
- else if (ymax < 10000)
- {
- snap = 100;
- }
- else
- {
- snap = 1000;
- }
- const float eps = snap / 100.0f;
- int label_ymax =
- (static_cast<int>((ymax - eps) / snap) + 1) * snap; // round up
- int label_ymin = static_cast<int>(ymin / snap) * snap; // round down
- float y_per_row = (label_ymax - label_ymin) * 1.0f / (h - 1);
- int actual_ymax = label_ymax + static_cast<int>(y_per_row / 2);
- int actual_ymin = label_ymin - static_cast<int>(y_per_row / 2);
- // 2. Print Y axis ticks
- for (int i = 0; i < h; i++)
- {
- char buf[10];
- snprintf(
- buf, sizeof(buf), "%-6d",
- static_cast<int>(Lerp(label_ymax, label_ymin, i * 1.0f / (h - 1))));
- mvwaddstr(win, i + y0, x0 + w - RIGHT_MARGIN + 1, buf);
- mvwaddch(win, i + y0, x0, '-');
- mvwaddch(win, i + y0, x0 + w - RIGHT_MARGIN, '-');
- }
- // 3. Go through the historical data and draw on the canvas
- for (int i = 0;
- i < std::min(static_cast<int>(data.size()), w - RIGHT_MARGIN - 1); i++)
- {
- float value = data[i];
- // antialiasing: todo for now
- // float value1 = value; // value1 is 1 column to the right
- // if (i > 0) value1 = data[i-1];
- int x = x0 + w - i - RIGHT_MARGIN - 1;
- float t = Map(value, actual_ymin, actual_ymax, 0, h, true);
- int row = static_cast<int>(t);
- float remaining = t - row;
- char ch; // Last filling character
- if (remaining >= 0.66f)
- {
- ch = ':';
- }
- else if (remaining >= 0.33f)
- {
- ch = '.';
- }
- else
- {
- ch = ' ';
- }
- int y = y0 + h - row - 1;
- mvwaddch(win, y, x, ch);
- for (int j = 0; j < row; j++)
- {
- mvwaddch(win, y + j + 1, x, ':');
- }
- }
-}
-
-template <typename T>
-void DrawHistogram(WINDOW* win, const Rect& rect, Histogram<T>* histogram)
-{
- // const int MARGIN = 7; // 5 digits margin
- const int LEFT_MARGIN = 7;
- // const int max_bucket_h = histogram->MaxBucketHeight();
- const int H_PAD = 0, V_PAD = 1;
- // x0, x1, y0 and y1 are the bounding box of the contents to be printed
- const int x0 = rect.x + H_PAD;
- const int x1 = rect.x + rect.w - H_PAD;
- const int y0 = rect.y + V_PAD;
- const int y1 = rect.y + rect.h - 1 - V_PAD;
- // Title
- wattron(win, A_BOLD | A_UNDERLINE);
- mvwaddstr(win, y0, x0, "Method Call Time (us) Histogram");
- wattrset(win, 0);
- // x2 is the beginning X of the histogram itself (not containing the margin)
- const int x2 = x0 + LEFT_MARGIN;
- if (histogram->Empty())
- {
- mvwaddstr(win, (y1 + y0) / 2, (x0 + x1) / 2, "(Empty)");
- return;
- }
- histogram->SetBucketCount(x1 - x2 + 1);
- histogram->ComputeHistogram();
- // Draw X axis labels
- char buf[22];
- snprintf(buf, sizeof(buf), "%.2f",
- static_cast<float>(histogram->LowPercentile()));
- mvwaddstr(win, y1, x0 + LEFT_MARGIN, buf);
- snprintf(buf, sizeof(buf), "%.2f",
- static_cast<float>(histogram->HighPercentile()));
- mvwaddstr(win, y1, x1 + 1 - strlen(buf), buf);
- snprintf(buf, sizeof(buf), "%d%%-%d%%",
- static_cast<int>(histogram->LowCumDensity() * 100),
- static_cast<int>(histogram->HighCumDensity() * 100));
- mvwaddstr(win, y1, x0, buf);
- // Draw Y axis labels
- const float hist_ymax = y1 - 1;
- const float hist_ymin = y0 + 1;
- const int max_histogram_h = histogram->MaxBucketHeight();
- if (hist_ymax <= hist_ymin)
- return; // Not enough space for rendering
- if (max_histogram_h <= 0)
- return;
- bool LOG_TRANSFORM = true;
- float lg_maxh = 0;
- if (LOG_TRANSFORM)
- {
- lg_maxh = log(max_histogram_h);
- }
- for (int y = hist_ymin; y <= hist_ymax; y++)
- {
- // There are (hist_ymax - hist_ymin + 1) divisions
- float fullness;
- fullness = (hist_ymax - y + 1) * 1.0f / (hist_ymax - hist_ymin + 1);
- int h;
- if (!LOG_TRANSFORM)
- {
- h = static_cast<int>(max_histogram_h * fullness);
- }
- else
- {
- h = static_cast<int>(exp(fullness * lg_maxh));
- }
- snprintf(buf, sizeof(buf), "%6d-", h);
- mvwaddstr(win, y, x0 + LEFT_MARGIN - strlen(buf), buf);
- }
- const int bar_height = hist_ymax - hist_ymin + 1; // Height of a full bar
- for (int x = x2, bidx = 0; x <= x1; x++, bidx++)
- {
- int h = histogram->BucketHeight(bidx);
- float lines_visible;
- if (!LOG_TRANSFORM)
- {
- lines_visible = h * 1.0f / max_histogram_h * bar_height;
- }
- else
- {
- if (h <= 0)
- lines_visible = 0;
- else
- lines_visible = log(h) * 1.0f / lg_maxh * bar_height;
- }
- // The histogram's top shall start from this line
- int y = hist_ymax - static_cast<int>(lines_visible);
- float y_frac = lines_visible - static_cast<int>(lines_visible);
- char ch; // Last filling character
- if (y >= hist_ymin)
- { // At the maximum bucket the Y overflows, so skip
- if (y_frac >= 0.66f)
- {
- ch = ':';
- }
- else if (y_frac >= 0.33f)
- {
- ch = '.';
- }
- else
- {
- if (y < hist_ymax)
- {
- ch = ' ';
- }
- else
- {
- if (y_frac > 0)
- {
- ch =
- '.'; // Makes long-tailed distribution easier to see
- }
- }
- }
- mvwaddch(win, y, x, ch);
- }
- y++;
- for (; y <= hist_ymax; y++)
- {
- mvwaddch(win, y, x, ':');
- }
- }
-}
-
-void SummaryView::UpdateDBusTopStatistics(DBusTopStatistics* stat)
-{
- if (!stat)
- return;
- float interval_secs = stat->seconds_since_last_sample_;
- if (interval_secs == 0)
- {
- interval_secs = GetSummaryIntervalInMillises() / 1000.0f;
- }
- // Per-second
- method_call_ = stat->num_mc_ / interval_secs;
- method_return_ = stat->num_mr_ / interval_secs;
- signal_ = stat->num_sig_ / interval_secs;
- error_ = stat->num_error_ / interval_secs;
- total_ = stat->num_messages_ / interval_secs;
- g_bargraph->AddValue(total_);
-}
-
-std::string Ellipsize(const std::string& s, int len_limit)
-{
- if (len_limit <= 3)
- return s.substr(0, len_limit);
- if (static_cast<int>(s.size()) < len_limit)
- {
- return s;
- }
- else
- {
- return s.substr(0, len_limit - 3) + "...";
- }
-}
-
-void SummaryView::Render()
-{
- // Draw text
- werase(win);
- if (!visible_)
- return;
- wattron(win, A_BOLD | A_UNDERLINE);
- mvwaddstr(win, 1, 1, "Message Type | msg/s");
- wattrset(win, 0);
- const int xend = 30;
- std::string s;
- s = FloatToString(method_call_);
- mvwaddstr(win, 2, 1, "Method Call");
- mvwaddstr(win, 2, xend - s.size(), s.c_str());
- s = FloatToString(method_return_);
- mvwaddstr(win, 3, 1, "Method Return ");
- mvwaddstr(win, 3, xend - s.size(), s.c_str());
- s = FloatToString(signal_);
- mvwaddstr(win, 4, 1, "Signal");
- mvwaddstr(win, 4, xend - s.size(), s.c_str());
- s = FloatToString(error_);
- mvwaddstr(win, 5, 1, "Error ");
- mvwaddstr(win, 5, xend - s.size(), s.c_str());
- wattron(win, A_UNDERLINE);
- s = FloatToString(total_);
- mvwaddstr(win, 6, 1, "Total");
- mvwaddstr(win, 6, xend - s.size(), s.c_str());
- wattroff(win, A_UNDERLINE);
- wattrset(win, 0);
- // Draw history bar graph
- Rect bargraph_rect = rect;
- const int bargraph_x = 64;
- bargraph_rect.x += bargraph_x;
- bargraph_rect.w -= bargraph_x;
- HistoryBarGraph(win, bargraph_rect, g_bargraph);
- // Draw histogram
- Rect histogram_rect = rect;
- histogram_rect.x += 32;
- histogram_rect.w = bargraph_rect.x - histogram_rect.x - 3;
- DrawHistogram(win, histogram_rect, g_histogram);
- // Draw border between summary and histogram
- for (int y = bargraph_rect.y; y <= bargraph_rect.y + bargraph_rect.h; y++)
- {
- mvwaddch(win, y, histogram_rect.x - 1, '|');
- mvwaddch(win, y, bargraph_rect.x - 1, '|');
- }
- DrawBorderIfNeeded();
- wrefresh(win);
-}
-
-void SensorDetailView::Render()
-{
- werase(win);
- if (!visible_)
- return;
- // If some sensor is focused, show details regarding that sensor
- if (state == SensorList)
- { // Otherwise show the complete list
- const int ncols = DispSensorsPerRow(); // Number of columns in viewport
- const int nrows = DispSensorsPerColumn(); // # rows in viewport
- int sensors_per_page = nrows * ncols;
- // Just in case the window gets invisibly small
- if (sensors_per_page < 1)
- return;
- int num_sensors = sensor_ids_.size();
- int total_num_columns = (num_sensors - 1) / nrows + 1;
- bool is_cursor_out_of_view = false;
- if (idx0 > choice_ || idx1 <= choice_)
- {
- is_cursor_out_of_view = true;
- }
- if (idx0 == INVALID || idx1 == INVALID)
- {
- is_cursor_out_of_view = true;
- }
- if (is_cursor_out_of_view)
- {
- idx0 = 0, idx1 = sensors_per_page;
- }
- while (idx1 <= choice_)
- {
- idx0 += nrows;
- idx1 += nrows;
- }
- const int y0 = 2; // to account for the border and info line
- const int x0 = 4; // to account for the left overflow marks
- int y = y0, x = x0;
- for (int i = 0; i < sensors_per_page; i++)
- {
- int idx = idx0 + i;
- if (idx < static_cast<int>(sensor_ids_.size()))
- {
- if (idx == choice_)
- {
- wattrset(win, A_REVERSE);
- }
- std::string s = sensor_ids_[idx];
- if (static_cast<int>(s.size()) > col_width) {
- s = s.substr(0, col_width - 2) + "..";
- } else {
- while (static_cast<int>(s.size()) < col_width)
- {
- s.push_back(' ');
- }
- }
- mvwaddstr(win, y, x, s.c_str());
- wattrset(win, 0);
- }
- else
- break;
- y++;
- if (i % nrows == nrows - 1)
- {
- y = y0;
- x += col_width + h_spacing;
- }
- }
- // Print overflow marks to the right of the screen
- for (int i = 0; i < nrows; i++)
- {
- int idx = idx0 + sensors_per_page + i;
- if (idx < num_sensors)
- {
- mvwaddch(win, y0 + i, x, '>');
- }
- }
- // Print overflow marks to the left of the screen
- for (int i = 0; i < nrows; i++)
- {
- int idx = idx0 - nrows + i;
- if (idx >= 0)
- {
- mvwaddch(win, y0 + i, 2, '<');
- }
- }
- // idx1 is one past the visible range, so no need to +1
- const int col0 = idx0 / nrows + 1, col1 = idx1 / nrows;
- mvwprintw(win, 1, 2, "Columns %d-%d of %d", col0, col1,
- total_num_columns);
- mvwprintw(win, 1, rect.w - 15, "%d sensors", sensor_ids_.size());
- }
- else if (state == SensorDetail)
- {
- // sensor_ids_ is the cached list of sensors, it should be the same size
- // as the actual number of sensors in the snapshot
- mvwprintw(win, 1, 2, "Details of sensor %s", curr_sensor_id_.c_str());
- mvwprintw(win, 1, rect.w - 15, "Sensor %d/%u", choice_ + 1,
- sensor_ids_.size()); // 1-based
- std::vector<Sensor*> sensors =
- g_sensor_snapshot->FindSensorsBySensorID(curr_sensor_id_);
- const int N = static_cast<int>(sensors.size());
- const int w = rect.w - 5;
- mvwprintw(win, 3, 2, "There are %d sensors with the name %s", N,
- curr_sensor_id_.c_str());
- int y = 5;
- int x = 2;
- if (N > 0)
- {
- for (int j = 0; j < N; j++)
- {
- Sensor* sensor = sensors[j];
- mvwprintw(win, y, x, "%d/%d", j + 1, N);
- char buf[200];
- snprintf(buf, sizeof(buf), "DBus Service : %s",
- sensor->ServiceName().c_str());
- y += DrawTextWithWidthLimit(win, buf, y, x, w, "/");
- snprintf(buf, sizeof(buf), "DBus Connection : %s",
- sensor->ConnectionName().c_str());
- y += DrawTextWithWidthLimit(win, buf, y, x, w, "/");
- snprintf(buf, sizeof(buf), "DBus Object Path: %s",
- sensor->ObjectPath().c_str());
- y += DrawTextWithWidthLimit(win, buf, y, x, w, "/");
- y++;
- }
- }
- else
- {
- mvwaddstr(win, y, x, "Sensor details not found");
- }
- }
- DrawBorderIfNeeded();
- wrefresh(win);
-}
-
-std::string SensorDetailView::GetStatusString()
-{
- if (state == SensorList)
- {
- return "[Arrow Keys]=Move Cursor [Q]=Deselect [Enter]=Show Sensor "
- "Detail";
- }
- else
- {
- return "[Arrow Keys]=Cycle Through Sensors [Esc/Q]=Exit";
- }
-}
-
-DBusStatListView::DBusStatListView() : DBusTopWindow()
-{
- highlight_col_idx_ = 0;
- sort_col_idx_ = 0;
- sort_order_ = SortOrder::Ascending;
- horizontal_pan_ = 0;
- row_idx_ = INVALID;
- disp_row_idx_ = 0;
- horizontal_pan_ = 0;
- menu1_ = new ArrowKeyNavigationMenu(this);
- menu2_ = new ArrowKeyNavigationMenu(this);
- // Load all available field names
- std::set<std::string> inactive_fields;
- std::set<std::string> active_fields;
-
- // Default choice of field names
- const int N = static_cast<int>(sizeof(FieldNames) / sizeof(FieldNames[0]));
- for (int i = 0; i < N; i++)
- {
- inactive_fields.insert(FieldNames[i]);
- }
- for (const std::string& s :
- dbus_top_analyzer::g_dbus_statistics.GetFieldNames())
- {
- inactive_fields.erase(s);
- active_fields.insert(s);
- }
- for (int i = 0; i < N; i++)
- {
- const std::string s = FieldNames[i];
- if (inactive_fields.count(s) > 0)
- {
- menu1_->AddItem(s);
- }
- else
- {
- menu2_->AddItem(s);
- }
- }
-
- curr_menu_state_ = LeftSide;
- menu_h_ = 5;
- menu_w_ = 24; // Need at least 2*padding + 15 for enough space, see menu.hpp
- menu_margin_ = 6;
- // Populate preferred column widths
- for (int i = 0; i < N; i++)
- {
- column_widths_[FieldNames[i]] = FieldPreferredWidths[i];
- }
-}
-
-std::pair<int, int> DBusStatListView::GetXSpanForColumn(const int col_idx)
-{
- std::vector<int> cw = ColumnWidths();
- if (col_idx < 0 || col_idx >= static_cast<int>(cw.size()))
- {
- return std::make_pair(INVALID, INVALID);
- }
- int x0 = 0, x1 = 0;
- for (int i = 0; i < col_idx; i++)
- {
- if (i > 0)
- {
- x0 += cw[i];
- }
- }
- x1 = x0 + cw[col_idx] - 1;
- return std::make_pair(x0, x1);
-}
-
-// If tolerance > 0, consider overlap before 2 intervals intersect
-// If tolerance ==0, consider overlap if 2 intervals exactly intersect
-// If tolerance < 0, consider overlap if Minimal Translate Distance is >=
-// -threshold
-bool IsSpansOverlap(const std::pair<int, int>& s0,
- const std::pair<int, int>& s1, int tolerance)
-{
- if (tolerance >= 0)
- {
- if (s0.second < s1.first - tolerance)
- return false;
- else if (s1.second < s0.first - tolerance)
- return false;
- else
- return true;
- }
- else
- {
- // Compute overlapping distance
- std::vector<std::pair<int, int>> tmp(
- 4); // [x, 1] means the start of interval
- // [x,-1] means the end of interval
- tmp[0] = std::make_pair(s0.first, 1);
- tmp[1] = std::make_pair(s0.second, -1);
- tmp[2] = std::make_pair(s1.first, 1);
- tmp[3] = std::make_pair(s1.second, -1);
- std::sort(tmp.begin(), tmp.end());
- int overlap_x0 = -INVALID, overlap_x1 = -INVALID;
- int idx = 0;
- const int N = static_cast<int>(tmp.size());
- int level = 0;
- while (idx < N)
- {
- const int x = tmp[idx].first;
- while (idx < N && x == tmp[idx].first)
- {
- level += tmp[idx].second;
- idx++;
- }
- // The starting position of the overlap
- if (level == 2)
- {
- overlap_x0 = idx - 1;
- }
- // The ending position of the overlap
- if (overlap_x0 != -INVALID && level < 2 && overlap_x1 == -INVALID)
- {
- overlap_x1 = idx - 1;
- }
- }
- const int overlap_length = overlap_x1 - overlap_x0 + 1;
- if (overlap_length >= -tolerance)
- return true;
- else
- return false;
- }
-}
-
-bool DBusStatListView::IsXSpanVisible(const std::pair<int, int>& xs,
- int tolerance)
-{
- const std::pair<int, int> vxs = {horizontal_pan_, horizontal_pan_ + rect.w};
- return IsSpansOverlap(xs, vxs, tolerance);
-}
-std::vector<std::string> DBusStatListView::ColumnHeaders()
-{
- return visible_columns_;
-}
-
-std::vector<int> DBusStatListView::ColumnWidths()
-{
- std::vector<int> widths = {8}; // for "Msg/s"
- std::vector<std::string> agg_headers = visible_columns_;
- std::vector<int> agg_widths(agg_headers.size(), 0);
- for (int i = 0; i < static_cast<int>(agg_headers.size()); i++)
- {
- agg_widths[i] = column_widths_[agg_headers[i]];
- }
- widths.insert(widths.end(), agg_widths.begin(), agg_widths.end());
- return widths;
-}
-
-// Coordinate systems are in world space, +x faces to the right
-// Viewport: [horizontal_pan_, horizontal_pan_ + rect.w]
-// Contents: [ column_width[0] ][ column_width[1] ][ column_width[2] ]
-void DBusStatListView::PanViewportOrMoveHighlightedColumn(const int delta_x)
-{
- // If the column to the left is visible, highlight it
- const int N = static_cast<int>(ColumnHeaders().size());
- bool col_idx_changed = false;
- if (delta_x < 0)
- { // Pan left
- if (highlight_col_idx_ > 0)
- {
- std::pair<int, int> xs_left =
- GetXSpanForColumn(highlight_col_idx_ - 1);
- if (IsXSpanVisible(xs_left, -1))
- {
- highlight_col_idx_--;
- col_idx_changed = true;
- }
- }
- if (!col_idx_changed)
- {
- horizontal_pan_ += delta_x;
- }
- }
- else if (delta_x > 0)
- { // Pan right
- if (highlight_col_idx_ < N - 1)
- {
- std::pair<int, int> xs_right =
- GetXSpanForColumn(highlight_col_idx_ + 1);
- if (IsXSpanVisible(xs_right, -1))
- {
- highlight_col_idx_++;
- col_idx_changed = true;
- }
- }
- if (!col_idx_changed)
- {
- horizontal_pan_ += delta_x;
- }
- }
-}
-
-void DBusStatListView::OnKeyDown(const std::string& key)
-{
- {
- switch (curr_menu_state_)
- {
- case LeftSide:
- {
- if (key == "up")
- {
- menu1_->OnKeyDown("up");
- }
- else if (key == "down")
- {
- menu1_->OnKeyDown("down");
- }
- else if (key == "right")
- {
- SetMenuState(RightSide);
- }
- else if (key == "enter")
- {
- SetMenuState(Hidden);
- }
- else if (key == "space")
- {
- std::string ch;
- if (menu1_->RemoveHighlightedItem(&ch))
- {
- menu2_->AddItem(ch);
- }
- }
- break;
- }
- case RightSide:
- {
- if (key == "up")
- {
- menu2_->OnKeyDown("up");
- }
- else if (key == "down")
- {
- menu2_->OnKeyDown("down");
- }
- else if (key == "left")
- {
- SetMenuState(LeftSide);
- }
- else if (key == "enter")
- {
- SetMenuState(Hidden);
- }
- else if (key == "space")
- {
- std::string ch;
- if (menu2_->RemoveHighlightedItem(&ch))
- {
- menu1_->AddItem(ch);
- }
- }
- break;
- }
- case Hidden:
- {
- if (key == "enter")
- {
- switch (last_menu_state_)
- {
- case LeftSide:
- case RightSide:
- SetMenuState(last_menu_state_);
- break;
- default:
- SetMenuState(LeftSide);
- }
- }
- else if (key == "left")
- {
- PanViewportOrMoveHighlightedColumn(-2);
- }
- else if (key == "right")
- {
- PanViewportOrMoveHighlightedColumn(2);
- }
- else if (key == "up")
- {
- disp_row_idx_--;
- if (disp_row_idx_ < 0)
- {
- disp_row_idx_ = 0;
- }
- }
- else if (key == "down")
- {
- disp_row_idx_++;
- const int N = static_cast<int>(stats_snapshot_.size());
- if (disp_row_idx_ >= N)
- {
- disp_row_idx_ = N - 1;
- }
- }
- else if (key == "a")
- {
- sort_order_ = SortOrder::Ascending;
- sort_col_idx_ = highlight_col_idx_;
- break;
- }
- else if (key == "d")
- {
- sort_order_ = SortOrder::Descending;
- sort_col_idx_ = highlight_col_idx_;
- break;
- }
- break;
- }
- }
- }
- Render();
-}
-
-// Window C
-void DBusStatListView::Render()
-{
- werase(win);
- if (!visible_)
- return;
- int num_lines_shown = rect.h - 3;
- if (curr_menu_state_ == LeftSide || curr_menu_state_ == RightSide)
- {
- menu1_->Render();
- menu2_->Render();
- num_lines_shown -= (menu_h_ + 3);
- // Draw the arrow
- const int x1 = menu1_->rect_.x;
- const int h1 = menu1_->rect_.h;
- const int x2 = menu2_->rect_.x;
- const int w2 = menu2_->rect_.w;
- const int y1 = menu1_->rect_.y;
- const int arrow_x = (x1 + x2 + w2) / 2 - 2;
- const int arrow_y = y1 + 2;
- const int caption_x = x1;
- const int caption_y = y1 + h1;
- for (int x = 1; x < rect.w - 1; x++)
- {
- mvwaddch(win, y1 - 3, x, '-');
- }
- mvwaddstr(win, y1 - 3, arrow_x - 8, "Press [Enter] to show/hide");
- mvwaddstr(win, y1 - 2, caption_x - 5,
- "DBus fields for aggregating and sorting results:");
- if (curr_menu_state_ == LeftSide)
- {
- mvwaddstr(win, y1 - 1, x1 - 4, "--[ Available Fields ]--");
- mvwaddstr(win, y1 - 1, x2 - 4, "--- Active Fields ---");
- }
- else
- {
- mvwaddstr(win, y1 - 1, x1 - 4, "--- Available Fields ---");
- mvwaddstr(win, y1 - 1, x2 - 4, "--[ Active Fields ]--");
- }
- if (curr_menu_state_ == LeftSide)
- {
- mvwaddstr(win, arrow_y, arrow_x, "-->");
- mvwaddstr(win, caption_y, caption_x,
- "Press [Space] to move to the right");
- }
- else
- {
- mvwaddstr(win, arrow_y, arrow_x, "<--");
- mvwaddstr(win, caption_y, caption_x,
- "Press [Space] to move to the left");
- }
- }
- std::vector<std::string> headers;
- std::vector<int> widths;
- visible_columns_ = g_dbus_statistics->GetFieldNames();
- std::vector<std::string> agg_headers = visible_columns_;
- std::vector<int> agg_widths(agg_headers.size(), 0);
- for (int i = 0; i < static_cast<int>(agg_headers.size()); i++)
- {
- agg_widths[i] = column_widths_[agg_headers[i]];
- }
- headers.insert(headers.end(), agg_headers.begin(), agg_headers.end());
- widths.insert(widths.end(), agg_widths.begin(), agg_widths.end());
- std::vector<int> xs;
- int curr_x = 2 - horizontal_pan_;
- for (const int w : widths)
- {
- xs.push_back(curr_x);
- curr_x += w;
- }
- const int N = headers.size();
- // Bound col_idx_
- if (highlight_col_idx_ >= N)
- {
- highlight_col_idx_ = N - 1;
- }
- // Render column headers
- for (int i = 0; i < N; i++)
- {
- std::string s = headers[i];
- // 1 char outside boundary = start printing from the second character,
- // etc
-
- // Print "<" for Ascending order (meaning: row 0 < row 1 < row 2 ... )
- // Print ">" for Descending order (meaning: row 0 > row 1 > row 2 ... )
- if (sort_col_idx_ == i)
- {
- if (sort_order_ == SortOrder::Ascending)
- {
- s.push_back('<');
- }
- else
- {
- s.push_back('>');
- }
- }
-
- // Highlight the "currently-selected column"
- if (highlight_col_idx_ == i)
- {
- wattrset(win, 0);
- wattron(win, A_REVERSE);
- }
- else
- {
- wattrset(win, 0);
- wattron(win, A_UNDERLINE);
- }
- int x = xs[i];
- if (x < 0)
- {
- if (-x < static_cast<int>(s.size()))
- {
- s = s.substr(-x);
- }
- else
- s = "";
- x = 0;
- }
- mvwaddstr(win, 1, x, s.c_str());
- }
- wattrset(win, 0);
- // Time since the last update of Window C
- float interval_secs = g_dbus_statistics->seconds_since_last_sample_;
- if (interval_secs == 0)
- {
- interval_secs = GetSummaryIntervalInMillises() / 1000.0f;
- }
-
- stats_snapshot_ = g_dbus_statistics->StatsSnapshot();
- const int nrows = static_cast<int>(stats_snapshot_.size());
- const std::vector<DBusTopSortField> fields = g_dbus_statistics->GetFields();
- const int ncols = static_cast<int>(fields.size());
- // Merge the list of DBus Message properties & computed metrics together
- std::map<std::vector<std::string>, DBusTopComputedMetrics>::iterator itr =
- stats_snapshot_.begin();
- struct StringOrFloat
- { // Cannot use union so using struct
- std::string s;
- float f;
- };
-
- // "Stage" the snapshot for displaying in the form of a spreadsheet
- std::vector<std::pair<StringOrFloat, std::vector<std::string>>>
- stats_snapshot_staged;
- const DBusTopSortField sort_field = fields[sort_col_idx_];
- const bool is_sort_key_numeric = DBusTopSortFieldIsNumeric(sort_field);
-
- for (int i = 0; i < nrows; i++) // One row of cells
- {
- int idx0 = 0; // indexing into the std::vector<string> of each row
- std::vector<std::string> row;
-
- StringOrFloat sort_key; // The key used for sorting
- for (int j = 0; j < ncols; j++) // one column in the row
- {
- DBusTopSortField field = fields[j];
- // Populate the content of stats_snapshot_staged
-
- StringOrFloat sof; // Represents this column
-
- // When we haven't used up all
- if (idx0 < static_cast<int>(itr->first.size()))
- {
- sof.s = itr->first[idx0];
- }
- switch (field)
- {
- case kSender: // string
- case kDestination: // string
- case kInterface: // string
- case kPath: // string
- case kMember: // string
- case kSenderPID: // numeric
- case kSenderCMD: // string
- row.push_back(itr->first[idx0]);
- idx0++;
- if (field == kSenderPID)
- {
- // Note: attempting to std::atof("(unknown)") on the BMC
- // will cause hang. And GDB won't show backtrace.
- if (sof.s == "(unknown)")
- {
- if (sort_order_ == Ascending)
- {
- sof.f = -1;
- }
- else
- {
- sof.f = 1e20;
- }
- }
- else
- {
- sof.f = std::atof(sof.s.c_str());
- }
- }
- break;
- case kMsgPerSec: // Compute "messages per second"
- {
- int numbers[] = {
- itr->second.num_method_calls,
- itr->second.num_method_returns,
- itr->second.num_signals,
- itr->second.num_errors,
- };
- int the_sum = 0; // For sorting
-
- std::string s; // String representation in the form or
- // "1.00/2.00/3.00/4.00"
- for (int i = 0; i < 4; i++)
- {
- the_sum += numbers[i];
- if (i > 0)
- s += "/";
- float per_sec = numbers[i] / interval_secs;
- s += FloatToString(per_sec);
- }
-
- row.push_back(s);
- sof.f = the_sum;
- break;
- }
- case kAverageLatency: // Compute "average Method Call latency"
- const DBusTopComputedMetrics& m = itr->second;
- if (m.num_method_calls == 0)
- {
- row.push_back("n/a");
- if (sort_order_ == Ascending)
- {
- sof.f = -1; // Put to the top
- }
- else
- {
- sof.f = 1e20; // Put to the top
- }
- }
- else
- {
- float avg_latency_usec =
- m.total_latency_usec / m.num_method_calls;
- row.push_back(FloatToString(avg_latency_usec));
- sof.f = avg_latency_usec;
- }
- break;
- }
- if (j == sort_col_idx_)
- {
- sort_key = sof;
- }
- }
- stats_snapshot_staged.push_back(std::make_pair(sort_key, row));
- itr++;
- }
-
- // Sort the "staged snapshot" using the sort_key, using different functions
- // depending on whether sort key is numeric or string
- if (is_sort_key_numeric)
- {
- std::sort(
- stats_snapshot_staged.begin(), stats_snapshot_staged.end(),
- [](const std::pair<StringOrFloat, std::vector<std::string>>& a,
- const std::pair<StringOrFloat, std::vector<std::string>>& b) {
- return a.first.f < b.first.f;
- });
- }
- else
- {
- std::sort(
- stats_snapshot_staged.begin(), stats_snapshot_staged.end(),
- [](const std::pair<StringOrFloat, std::vector<std::string>>& a,
- const std::pair<StringOrFloat, std::vector<std::string>>& b) {
- return a.first.s < b.first.s;
- });
- }
-
- if (sort_order_ == Descending)
- {
- std::reverse(stats_snapshot_staged.begin(),
- stats_snapshot_staged.end());
- }
- // Minus 2 because of "msgs/s" and "+"
- const int num_fields = N;
- // The Y span of the area for rendering the "spreadsheet"
- const int y0 = 2, y1 = y0 + num_lines_shown - 1;
- // Key is sender, destination, interface, path, etc
- for (int i = 0, shown = 0;
- i + disp_row_idx_ < static_cast<int>(stats_snapshot_staged.size()) &&
- shown < num_lines_shown;
- i++, shown++)
- {
- std::string s;
- int x = 0;
- const std::vector<std::string> key =
- stats_snapshot_staged[i + disp_row_idx_].second;
- for (int j = 0; j < num_fields; j++)
- {
- x = xs[j];
- s = key[j];
- // Determine column width limit for this particular column
- int col_width = 100;
- if (j < num_fields - 1)
- {
- col_width = xs[j + 1] - xs[j] - 1;
- }
- s = Ellipsize(s, col_width);
- if (x < 0)
- {
- if (-x < static_cast<int>(s.size()))
- s = s.substr(-x);
- else
- s = "";
- x = 0;
- }
- // Trim if string overflows to the right
- if (x + static_cast<int>(s.size()) > rect.w)
- {
- s = s.substr(0, rect.w - x);
- }
- mvwaddstr(win, 2 + i, x, s.c_str());
- }
- }
- // Overflows past the top ...
- if (disp_row_idx_ > 0)
- {
- std::string x = " [+" + std::to_string(disp_row_idx_) + " rows above]";
- mvwaddstr(win, y0, rect.w - static_cast<int>(x.size()) - 1, x.c_str());
- }
- // Overflows past the bottom ...
- const int last_disp_row_idx = disp_row_idx_ + num_lines_shown - 1;
- if (last_disp_row_idx < nrows - 1)
- {
- std::string x = " [+" +
- std::to_string((nrows - 1) - last_disp_row_idx) +
- " rows below]";
- mvwaddstr(win, y1, rect.w - static_cast<int>(x.size()) - 1, x.c_str());
- }
- DrawBorderIfNeeded();
- wrefresh(win);
-}
-
-void DBusStatListView::OnResize(int win_w, int win_h)
-{
- rect.y = 8 - MARGIN_BOTTOM;
- rect.w = win_w - (win_w / 2) + 1; // Perfectly overlap on the vertical edge
- rect.x = win_w - rect.w;
- rect.h = win_h - rect.y - MARGIN_BOTTOM;
- const int x0 = rect.w / 2 - menu_w_ - menu_margin_ / 2;
- const int x1 = x0 + menu_margin_ + menu_w_;
- const int menu_y = rect.h - menu_h_;
- menu1_->SetRect(Rect(x0, menu_y, menu_w_, menu_h_)); // Local coordinates
- menu1_->SetOrder(ArrowKeyNavigationMenu::Order::ColumnMajor);
- menu2_->SetRect(Rect(x1, menu_y, menu_w_, menu_h_));
- menu2_->SetOrder(ArrowKeyNavigationMenu::Order::ColumnMajor);
- UpdateWindowSizeAndPosition();
-}
-
-std::vector<DBusTopSortField> DBusStatListView::GetSortFields()
-{
- std::vector<DBusTopSortField> ret;
- const int N = sizeof(FieldNames) / sizeof(FieldNames[0]);
- for (const std::string& s : menu2_->Items())
- {
- for (int i = 0; i < N; i++)
- {
- if (FieldNames[i] == s)
- {
- ret.push_back(static_cast<DBusTopSortField>(i));
- break;
- }
- }
- }
- return ret;
-}
-
-std::string DBusStatListView::GetStatusString()
-{
- if (curr_menu_state_ == LeftSide || curr_menu_state_ == RightSide)
- {
- return "[Enter]=Hide Panel [Space]=Choose Entry [Arrow Keys]=Move "
- "Cursor";
- }
- else
- {
- return "[Enter]=Show Column Select Panel [Arrow Keys]=Pan View";
- }
-}
-
-void FooterView::Render()
-{
- werase(win);
- const time_t now = time(nullptr);
- const char* date_time = ctime(&now);
- wattrset(win, 0);
- std::string help_info;
- if (g_current_active_view == nullptr)
- {
- help_info = "Press [Tab] to cycle through views";
- }
- else
- {
- help_info = g_current_active_view->GetStatusString();
- }
- mvwaddstr(win, 0, 1, date_time);
- mvwaddstr(win, 0, rect.w - int(help_info.size()) - 1, help_info.c_str());
- wrefresh(win);
-}
diff --git a/dbus-top/views.hpp b/dbus-top/views.hpp
deleted file mode 100644
index d4f3779..0000000
--- a/dbus-top/views.hpp
+++ /dev/null
@@ -1,539 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "analyzer.hpp"
-#include "bargraph.hpp"
-#include "main.hpp"
-#include "menu.hpp"
-#include "sensorhelper.hpp"
-
-#include <ncurses.h>
-#include <string>
-#include <vector>
-constexpr int MARGIN_BOTTOM = 1;
-class DBusTopWindow
-{
- public:
- DBusTopWindow()
- {
- win = newwin(25, 80, 0, 0); // Default to 80x25, will be updated
- has_border_ = true;
- focused_ = false;
- selectable_ = true;
- visible_ = true;
- maximize_ = false;
- }
-
- virtual ~DBusTopWindow()
- {}
- virtual void OnKeyDown(const std::string& key) = 0;
- virtual void Render() = 0;
- virtual void OnResize(int win_w, int win_h) = 0;
- void UpdateWindowSizeAndPosition()
- {
- mvwin(win, rect.y, rect.x);
- wresize(win, rect.h, rect.w);
- }
-
- void DrawBorderIfNeeded()
- {
- if (focused_)
- {
- wborder(win, '*', '*', '*', '*', '*', '*', '*', '*');
- }
- else
- {
- wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
- }
- wrefresh(win);
- }
-
- virtual void RecreateWindow()
- {
- delwin(win);
- win = newwin(25, 80, 0, 0);
- UpdateWindowSizeAndPosition();
- }
-
- virtual std::string GetStatusString() = 0;
- WINDOW* win;
- Rect rect;
- bool has_border_;
- bool focused_;
- bool selectable_;
- bool maximize_;
- bool visible_;
-};
-
-class SummaryView : public DBusTopWindow
-{
- public:
- SummaryView() : DBusTopWindow()
- {}
- void Render() override;
- void OnResize(int win_w, int win_h) override
- {
- rect.h = 8;
- rect.w = win_w;
- rect.x = 0;
- rect.y = 0;
- UpdateWindowSizeAndPosition();
- }
-
- void UpdateDBusTopStatistics(DBusTopStatistics* stat);
- void OnKeyDown(const std::string& key) override
- {}
- std::string GetStatusString() override
- {
- return "Summary View";
- }
-
- private:
- float method_call_, method_return_, signal_, error_, total_;
-};
-
-class SensorDetailView : public DBusTopWindow
-{
- public:
- SensorDetailView() : DBusTopWindow()
- {
- choice_ = -999; // -999 means invalid
- h_padding = 2;
- h_spacing = 3;
- col_width = 15;
- idx0 = idx1 = -999;
- state = SensorList;
- }
-
- void Render() override;
- int DispSensorsPerColumn()
- {
- return rect.h - 3;
- }
-
- int DispSensorsPerRow()
- {
- int ncols = 0;
- while (true)
- {
- int next = ncols + 1;
- int w = 2 * h_padding + col_width * next;
- if (next > 1)
- w += (next - 1) * h_spacing;
- if (w <= rect.w - 2)
- {
- ncols = next;
- }
- else
- {
- break;
- }
- }
- return ncols;
- }
-
- void OnKeyDown(const std::string& key) override
- {
- if (state == SensorList)
- { // Currently in sensor list
- if (key == "right")
- {
- MoveChoiceCursorHorizontally(1);
- }
- else if (key == "left")
- {
- MoveChoiceCursorHorizontally(-1);
- }
- else if (key == "up")
- {
- MoveChoiceCursor(-1, true);
- }
- else if (key == "down")
- {
- MoveChoiceCursor(1, true);
- }
- else if (key == "enter")
- {
- if (choice_ != -999)
- {
- state = SensorDetail;
- }
- }
- else if (key == "escape")
- {
- choice_ = -999;
- }
- }
- else if (state == SensorDetail)
- { // Currently focusing on a sensor
- if (key == "right" || key == "down")
- {
- MoveChoiceCursor(1, true);
- }
- else if (key == "left" || key == "up")
- {
- MoveChoiceCursor(-1, true);
- }
- else if (key == "escape")
- {
- state = SensorList;
- }
- }
-
- Render(); // This window is already on top, redrawing won't corrupt
- }
-
- void MoveChoiceCursor(int delta, bool wrap_around = true)
- {
- const int ns = sensor_ids_.size();
- if (ns < 1)
- return;
- // First of all, if cursor is inactive, activate it
- if (choice_ == -999)
- {
- if (delta > 0)
- {
- choice_ = 0;
- curr_sensor_id_ = sensor_ids_[0];
- return;
- }
- else
- {
- choice_ = ns - 1;
- curr_sensor_id_ = sensor_ids_.back();
- return;
- }
- }
- int choice_next = choice_ + delta;
- while (choice_next >= ns)
- {
- if (wrap_around)
- {
- choice_next -= ns;
- }
- else
- {
- choice_next = ns - 1;
- }
- }
- while (choice_next < 0)
- {
- if (wrap_around)
- {
- choice_next += ns;
- }
- else
- {
- choice_next = 0;
- }
- }
- choice_ = choice_next;
- curr_sensor_id_ = sensor_ids_[choice_];
- }
-
- void MoveChoiceCursorHorizontally(int delta)
- {
- if (delta != 0 && delta != -1 && delta != 1)
- return;
- const int ns = sensor_ids_.size();
- if (ns < 1)
- return;
- if (choice_ == -999)
- {
- if (delta > 0)
- {
- choice_ = 0;
- curr_sensor_id_ = sensor_ids_[0];
- return;
- }
- else
- {
- curr_sensor_id_ = sensor_ids_.back();
- choice_ = ns - 1;
- return;
- }
- }
- const int nrows = DispSensorsPerColumn();
- int tot_columns = (ns - 1) / nrows + 1;
- int num_rows_last_column = ns - nrows * (tot_columns - 1);
- int y = choice_ % nrows, x = choice_ / nrows;
- if (delta == 1)
- {
- x++;
- }
- else
- {
- x--;
- }
- bool overflow_to_right = false;
- if (y < num_rows_last_column)
- {
- if (x >= tot_columns)
- {
- overflow_to_right = true;
- }
- }
- else
- {
- if (x >= tot_columns - 1)
- {
- overflow_to_right = true;
- }
- }
- bool overflow_to_left = false;
- if (x < 0)
- {
- overflow_to_left = true;
- }
- {
- if (overflow_to_right)
- {
- y++;
- // overflow past the right of window
- // Start probing next line
- if (y >= nrows)
- {
- choice_ = 0;
- return;
- }
- else
- {
- choice_ = y;
- return;
- }
- }
- else if (overflow_to_left)
- { // overflow past the left of window
- y--;
- if (y < 0)
- { // overflow past the top of window
- // Focus on the visually bottom-right entry
- if (num_rows_last_column == nrows)
- { // last col fully populated
- choice_ = ns - 1;
- }
- else
- { // last column is not fully populated
- choice_ = ns - num_rows_last_column - 1;
- }
- return;
- }
- else
- {
- if (y < num_rows_last_column)
- {
- choice_ = nrows * (tot_columns - 1) + y;
- }
- else
- {
- choice_ = nrows * (tot_columns - 2) + y;
- }
- }
- }
- else
- {
- choice_ = y + x * nrows;
- }
- }
- curr_sensor_id_ = sensor_ids_[choice_];
- }
-
- // Cache the sensor list in the sensor snapshot
- void UpdateSensorSnapshot(SensorSnapshot* snapshot)
- {
- std::string old_sensor_id = "";
- if (choice_ != -999)
- {
- old_sensor_id = sensor_ids_[choice_];
- }
- std::vector<std::string> new_sensors =
- snapshot->GetDistinctSensorNames();
- if (new_sensors == sensor_ids_)
- {
- return; // Nothing is changed
- }
- // Assume changed
- sensor_ids_ = new_sensors;
- choice_ = -999;
- for (int i = 0; i < static_cast<int>(new_sensors.size()); i++)
- {
- if (new_sensors[i] == old_sensor_id)
- {
- choice_ = i;
- break;
- curr_sensor_id_ = sensor_ids_[choice_];
- }
- }
- }
-
- void OnResize(int win_w, int win_h) override
- {
- rect.x = 0;
- rect.y = 8 - MARGIN_BOTTOM;
- rect.w = win_w / 2;
- rect.h = win_h - rect.y - MARGIN_BOTTOM;
- UpdateWindowSizeAndPosition();
- }
-
- std::vector<std::string> sensor_ids_;
- // We need to keep track of the currently-selected sensor ID because
- // the sensor ID might theoretically become invalidated at any moment, and
- // we should allow the UI to show an error gracefully in that case.
- std::string curr_sensor_id_;
- int choice_;
- int h_padding;
- int h_spacing;
- int col_width;
- int idx0, idx1; // Range of sensors on display
- enum State
- {
- SensorList,
- SensorDetail,
- };
-
- State state;
- std::string GetStatusString() override;
-};
-
-class DBusStatListView : public DBusTopWindow
-{
- public:
- DBusStatListView();
- void Render() override;
- void OnResize(int win_w, int win_h) override;
- void OnKeyDown(const std::string& key) override;
- int horizontal_pan_;
- int menu_h_, menu_w_, menu_margin_;
- ArrowKeyNavigationMenu* menu1_;
- ArrowKeyNavigationMenu* menu2_;
- int highlight_col_idx_; // Currently highlighted column
- int row_idx_; // Currently highlighted row
-
- int sort_col_idx_; // Column used for sorting
- enum SortOrder
- {
- Ascending,
- Descending,
- };
- SortOrder sort_order_;
-
- int disp_row_idx_; // From which row to start displaying? (essentially a
- // vertical scroll bar)
- int last_choices_[2]; // Last choice index on either side
- enum MenuState
- {
- Hidden,
- LeftSide, // When the user is choosing an entry on the left side
- RightSide, // When the user is choosing an entry on the right side
- };
-
- std::vector<DBusTopSortField> GetSortFields();
- MenuState curr_menu_state_, last_menu_state_;
- std::string GetStatusString() override;
- void RecreateWindow()
- {
- delwin(win);
- win = newwin(25, 80, 0, 0);
- menu1_->win_ = win;
- menu2_->win_ = win;
- UpdateWindowSizeAndPosition();
- }
-
- private:
- void SetMenuState(MenuState s)
- {
- last_menu_state_ = curr_menu_state_;
- // Moving out from a certain side: save the last choice of that side
- switch (curr_menu_state_)
- {
- case LeftSide:
- if (s == RightSide)
- {
- last_choices_[0] = menu1_->Choice();
- menu1_->Deselect();
- }
- break;
- case RightSide:
- if (s == LeftSide)
- {
- last_choices_[1] = menu2_->Choice();
- menu2_->Deselect();
- }
- break;
- default:
- break;
- }
- // Moving into a certain side: save the cursor
- switch (s)
- {
- case LeftSide:
- if (!menu1_->Empty())
- {
- menu1_->SetChoiceAndConstrain(last_choices_[0]);
- }
- break;
- case RightSide:
- if (!menu2_->Empty())
- {
- menu2_->SetChoiceAndConstrain(last_choices_[1]);
- }
- break;
- default:
- break;
- }
- curr_menu_state_ = s;
- }
- void PanViewportOrMoveHighlightedColumn(const int delta_x);
- // ColumnHeaders and ColumnWidths are the actual column widths used for
- // display. They are "msg/s" or "I2c/s" prepended to the chosen set of
- // fields.
- std::vector<std::string> ColumnHeaders();
- std::vector<int> ColumnWidths();
- // X span, for checking visibility
- std::pair<int, int> GetXSpanForColumn(const int col_idx);
- bool IsXSpanVisible(const std::pair<int, int>& xs,
- const int tolerance); // uses horizontal_pan_
- std::vector<std::string> visible_columns_;
- std::unordered_map<std::string, int> column_widths_;
- std::map<std::vector<std::string>, DBusTopComputedMetrics> stats_snapshot_;
-};
-
-class FooterView : public DBusTopWindow
-{
- public:
- FooterView() : DBusTopWindow()
- {
- selectable_ = false; // Cannot be selected by the tab key
- }
-
- void OnKeyDown(const std::string& key) override
- {}
- void OnResize(int win_w, int win_h) override
- {
- rect.h = 1;
- rect.w = win_w;
- rect.x = 0;
- rect.y = win_h - 1;
- UpdateWindowSizeAndPosition();
- }
-
- void Render() override;
- std::string GetStatusString() override
- {
- return "";
- }
-
-};
diff --git a/dbus-top/xmlparse.cpp b/dbus-top/xmlparse.cpp
deleted file mode 100644
index 2e4b1a3..0000000
--- a/dbus-top/xmlparse.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "xmlparse.hpp"
-#include "main.hpp"
-
-int Munch(const std::string& sv, int* idx, std::string* out)
-{
- if (*idx >= static_cast<int>(sv.size()))
- return -INVALID;
- while (::isspace(sv[*idx]))
- {
- (*idx)++;
- }
- int ret = 0;
- *out = "";
- int quote_state = 0; // 0: not seen, 1: seen opening quotation, 2: ended
- while (*idx < static_cast<int>(sv.size()))
- {
- const char ch = sv[*idx];
- if (::isspace(ch) && quote_state != 1)
- {
- break;
- }
- (*idx)++;
- if (ch == '<')
- {
- if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '!')
- {
- ret = 10; // Comment
- }
- else if (*idx < static_cast<int>(sv.size()) && sv[*idx] == '/')
- {
- ret = 22; // Closing tag
- (*idx)++; // Skip the '/'
- }
- else
- {
- ret = 1; // <
- }
- }
- else if (ch == '>')
- {
- if (ret == 1)
- {
- ret = 12;
- } // < >
- else if (ret == 22)
- {}
- else
- ret = 2; // >
- if (out->size() == 0)
- {
- (*idx)++;
- }
- break; // Do not consume
- }
- else if (ch == '\"')
- {
- ret = 3; //
- switch (quote_state)
- {
- case 0:
- {
- quote_state = 1;
- continue;
- }
- case 1:
- {
- quote_state = 2;
- break;
- }
- }
- }
- else if (ch == '/' && *idx < static_cast<int>(sv.size()) &&
- sv[*idx] == '>')
- {
- ret = 22; // Closing tag
- (*idx)++;
- break;
- }
- else
- {
- out->push_back(ch);
- }
- }
- return ret;
-}
-
-XMLNode* ParseXML(const std::string& sv)
-{
- int verbose = 0;
- char* v = getenv("VERBOSE");
- if (v)
- {
- verbose = std::atoi(v);
- }
- int idx = 0;
- std::string out;
- int res;
- std::vector<std::string> tags;
- std::vector<XMLNode*> nodestack;
- XMLNode* root = nullptr;
- if (verbose > 0)
- {
- printf("%s\n", sv.c_str());
- }
- while ((res = Munch(sv, &idx, &out)) != -INVALID)
- {
- if (res == 1 || res == 12)
- {
- XMLNode* newnode = new XMLNode(out);
- if (tags.empty())
- {
- root = newnode;
- }
- else
- {
- nodestack.back()->AddChild(newnode);
- }
- tags.push_back(out);
- nodestack.push_back(newnode);
- }
-
- // Add name (has to be before pop_back)
- if (out.find("name=") == 0)
- {
- nodestack.back()->SetName(out.substr(5));
- }
-
- if (res == 22 && tags.size() > 0)
- {
- tags.pop_back();
- nodestack.pop_back();
- }
- if (verbose >= 2)
- {
- printf("Munch %d %s, tags:", res, out.c_str());
- for (const std::string& x : tags)
- {
- printf(" %s", x.c_str());
- }
- printf("\n");
- }
- }
- return root;
-}
-
-void DeleteTree(XMLNode* x)
-{
- for (XMLNode* ch : x->children)
- {
- DeleteTree(ch);
- }
- delete x;
-}
-
-std::vector<std::string> XMLNode::GetChildNodeNames()
-{
- std::vector<std::string> ret;
- for (XMLNode* n : children)
- {
- if (n->tag == "node")
- {
- ret.push_back(n->fields["name"]);
- }
- }
- return ret;
-}
-
-std::vector<std::string> XMLNode::GetInterfaceNames()
-{
- std::vector<std::string> ret;
- for (XMLNode* n : children)
- {
- if (n->tag == "interface")
- {
- ret.push_back(n->fields["name"]);
- }
- }
- return ret;
-}
\ No newline at end of file
diff --git a/dbus-top/xmlparse.hpp b/dbus-top/xmlparse.hpp
deleted file mode 100644
index 3a76e9a..0000000
--- a/dbus-top/xmlparse.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <map>
-#include <string>
-#include <vector>
-
-class XMLNode
-{
- public:
- std::string tag;
- std::map<std::string, std::string> fields;
- std::vector<XMLNode*> children;
- std::vector<XMLNode*> interfaces;
- XMLNode(const std::string& t) : tag(t)
- {}
-
- void AddChild(XMLNode* x)
- {
- children.push_back(x);
- }
-
- void do_Print(int indent)
- {
- for (int i = 0; i < indent; i++)
- printf(" ");
- printf("%s", tag.c_str());
- if (fields["name"] != "")
- {
- printf(" name=[%s]", fields["name"].c_str());
- }
- printf("\n");
- for (XMLNode* ch : children)
- {
- ch->do_Print(indent + 1);
- }
- }
-
- void Print()
- {
- do_Print(0);
- }
-
- void SetName(const std::string& n)
- {
- fields["name"] = n;
- }
-
- std::vector<std::string> GetChildNodeNames();
- std::vector<std::string> GetInterfaceNames();
-};
-
-XMLNode* ParseXML(const std::string& sv);
-void DeleteTree(XMLNode* x);