Populate info in background thread
This change incorporates
https://gerrit.openbmc.org/c/openbmc/openbmc-tools/+/50784 and
https://gerrit.openbmc.org/c/openbmc/openbmc-tools/+/50088.
The function `ListAllSensors` populates a list of DBus sensor objects.
Currently it runs in the main thread before the UI gets created.
To enhance user experience, this routine is moved to a separate thread,
so the information is populated by that thread, so the main thread does
not get blocked while the list is being filled.
Originally, change 50784's ListAllSensors function includes the
following steps:
1) List DBus connections currently on the Bus
2) Get Creds for each of the DBus connections
3) Examine objects in ObjectMapper to ..
* See if they are Sensor objects
* If so mark a "Sensor" as "visible in ObjectMapper"
4) List all Associations recorded in the ObjectMapper
* So they can be shown in the sensor info panel
5) Find association definitions
6) Find association endpoints
7) Check all objects from HwMon daemons
* Objects from the DBus-Sensors daemon will be added later
8) Check `ipmitool sdr`
Step 8) is currently removed in this change since running `ipmitool sdr`
can potentially take a long time.
Change-Id: If6f27f130060b52e22c405942a861ba40e45ced2
Signed-off-by: Sui Chen <suichen6@gmail.com>
diff --git a/analyzer.cpp b/analyzer.cpp
index dbcb754..80e22fc 100644
--- a/analyzer.cpp
+++ b/analyzer.cpp
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <atomic>
+#include <cassert>
#include <filesystem>
#include <fstream>
#include <functional>
@@ -30,10 +31,13 @@
#include <sstream>
#include <string>
+int AcquireBus(sd_bus** ret);
+
extern SensorSnapshot* g_sensor_snapshot;
extern DBusConnectionSnapshot* g_connection_snapshot;
extern sd_bus* g_bus;
extern SensorDetailView* g_sensor_detail_view;
+extern FooterView* g_footer_view;
static std::unordered_map<uint64_t, uint64_t>
in_flight_methodcalls; // serial => microseconds
@@ -134,7 +138,7 @@
}
std::vector<std::string> FindAllObjectPathsForService(
- const std::string& service,
+ sd_bus* bus, const std::string& service,
std::function<void(const std::string&, const std::vector<std::string>&)>
on_interface_cb)
{
@@ -155,34 +159,29 @@
{
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(),
+ 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);
+ r = sd_bus_call(bus, m, 0, &err, &reply);
if (r < 0)
{
- printf("Could not execute method call, r=%d, strerror=%s\n", r,
- strerror(-r));
+ continue;
}
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));
+ continue;
}
else
{
- XMLNode* t = ParseXML(s1);
+ XMLNode* t = ParseXML(std::string(s));
std::vector<std::string> ch = t->GetChildNodeNames();
if (on_interface_cb != nullptr)
{
@@ -207,12 +206,17 @@
return all_obj_paths;
}
-void ListAllSensors()
+void ListAllSensors(sd_bus* bus, DBusConnectionSnapshot** cxn_snapshot,
+ SensorSnapshot** sensor_snapshot)
{
- g_connection_snapshot = new DBusConnectionSnapshot();
- printf("1. Getting names\n");
+ // Craete new snapshots
+ (*cxn_snapshot) = new DBusConnectionSnapshot();
+ (*sensor_snapshot) = new SensorSnapshot(*cxn_snapshot);
+
+ g_footer_view->SetStatusString("1. Listing DBus Names");
+ DBusTopUpdateFooterView();
char** names;
- int r = sd_bus_list_names(g_bus, &names, nullptr);
+ int r = sd_bus_list_names(bus, &names, nullptr);
std::vector<std::string> services;
std::vector<int> pids;
std::vector<std::string> comms;
@@ -222,12 +226,22 @@
free(*ptr);
}
free(names);
- printf("2. Getting creds of each name\n");
- for (int i = 0; i < static_cast<int>(services.size()); i++)
+
+ g_footer_view->SetStatusString("2. Getting Creds");
+ DBusTopUpdateFooterView();
+ size_t N = services.size();
+ for (size_t i = 0; i < N; i++)
{
+ if (i == N - 1 || (i % 100) == 99)
+ {
+ g_footer_view->SetStatusString("2. Getting Creds " +
+ std::to_string(i + 1) + "/" +
+ std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
const std::string& service = services[i];
sd_bus_creds* creds = nullptr;
- r = sd_bus_get_name_creds(g_bus, services[i].c_str(),
+ r = sd_bus_get_name_creds(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 |
@@ -237,9 +251,7 @@
// 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);
@@ -268,89 +280,70 @@
{
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);
+ (*cxn_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");
+
+ g_footer_view->SetStatusString("3. Examine objects in ObjectMapper");
std::vector<std::string> all_obj_paths = FindAllObjectPathsForService(
- "xyz.openbmc_project.ObjectMapper", nullptr);
+ bus, "xyz.openbmc_project.ObjectMapper", nullptr);
+ N = all_obj_paths.size();
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)
+ for (size_t i = 0; i < N; i++)
{
+ if (i % 100 == 99 || i == N - 1)
+ {
+ g_footer_view->SetStatusString(
+ "3. Examine objects in ObjectMapper " + std::to_string(i + 1) +
+ "/" + std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
+
+ const std::string& p = all_obj_paths[i];
if (IsSensorObjectPath(p))
{
err = SD_BUS_ERROR_NULL;
r = sd_bus_message_new_method_call(
- g_bus, &m, "xyz.openbmc_project.ObjectMapper",
+ 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);
+ r = sd_bus_call(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)
@@ -359,8 +352,6 @@
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)
@@ -374,14 +365,11 @@
&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;
@@ -391,14 +379,11 @@
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"))
{
@@ -408,8 +393,9 @@
}
if (has_value_interface)
{
- g_sensor_snapshot->SerSensorVisibleFromObjectMapper(
- std::string(interface_map_first), p);
+ (*sensor_snapshot)
+ ->SetSensorVisibleFromObjectMapper(
+ std::string(interface_map_first), p);
}
r = sd_bus_message_exit_container(reply);
}
@@ -421,9 +407,389 @@
{}
}
}
- printf("4. Check Hwmon's DBus objects\n");
- for (int i = 0; i < int(comms.size()); i++)
+
+ g_footer_view->SetStatusString("4. List Associations in ObjectMapper");
+ DBusTopUpdateFooterView();
+ err = SD_BUS_ERROR_NULL;
+ r = sd_bus_message_new_method_call(
+ bus, &m, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
+ if (r < 0)
{
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(m, 's', "/");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ const int zero = 0;
+ r = sd_bus_message_append_basic(m, 'i', &zero);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(m, 's', "xyz.openbmc_project.Association");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_call(bus, m, 0, &err, &reply);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ const char* sig = sd_bus_message_get_signature(reply, 0);
+ if (strcmp(sig, "as"))
+ {
+ assert(0);
+ }
+ r = sd_bus_message_enter_container(reply, 'a', "s");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ std::set<std::string> assoc_paths;
+ while (true)
+ {
+ const char* p;
+ r = sd_bus_message_read_basic(reply, 's', &p);
+ if (r <= 0)
+ break;
+ else
+ {
+ assoc_paths.insert(p);
+ }
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ }
+
+ size_t idx = 0;
+ for (const std::string& assoc_path : assoc_paths)
+ {
+ if (idx % 100 == 99 || idx == N - 1)
+ {
+ g_footer_view->SetStatusString(
+ "4. List Associations in ObjectMapper " +
+ std::to_string(idx + 1) + "/" + std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
+ ++idx;
+ err = SD_BUS_ERROR_NULL;
+ r = sd_bus_message_new_method_call(
+ bus, &m, "xyz.openbmc_project.ObjectMapper", assoc_path.c_str(),
+ "org.freedesktop.DBus.Properties", "Get");
+ r = sd_bus_message_append_basic(m, 's',
+ "xyz.openbmc_project.Association");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(m, 's', "endpoints");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_call(bus, m, 0, &err, &reply);
+ if (r < 0)
+ {
+ // The object may not have any endpoints
+ continue;
+ }
+ const char* sig = sd_bus_message_get_signature(reply, 0);
+ if (strcmp(sig, "v"))
+ {
+ assert(0);
+ }
+ r = sd_bus_message_enter_container(reply, 'v', "as");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_enter_container(reply, 'a', "s");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ std::set<std::string> entries;
+ while (true)
+ {
+ const char* p;
+ r = sd_bus_message_read_basic(reply, 's', &p);
+ if (r <= 0)
+ break;
+ entries.insert(p);
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ }
+
+ (*sensor_snapshot)->AddAssociationEndpoints(assoc_path, entries);
+ }
+
+ g_footer_view->SetStatusString("5. Find Association Definitions");
+ DBusTopUpdateFooterView();
+
+ err = SD_BUS_ERROR_NULL;
+ r = sd_bus_message_new_method_call(
+ bus, &m, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree");
+ std::vector<std::pair<std::string, std::string>>
+ services_and_objects; // Record the Associations from those pairs
+ r = sd_bus_message_append_basic(m, 's', "/");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(m, 'i', &zero);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(
+ m, 's', "xyz.openbmc_project.Association.Definitions");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_call(bus, m, 0, &err, &reply);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ sig = sd_bus_message_get_signature(reply, 0);
+ if (strcmp(sig, "a{sa{sas}}"))
+ {
+ assert(0);
+ }
+ r = sd_bus_message_enter_container(reply, 'a', "{sa{sas}}");
+ if (r <= 0)
+ {
+ assert(0);
+ }
+
+ idx = 0;
+ N = services_and_objects.size();
+ while (true)
+ {
+ if (idx % 100 == 99 || idx == N - 1)
+ {
+ g_footer_view->SetStatusString("5. Find Association Definitions " +
+ std::to_string(idx + 1) + "/" +
+ std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
+ r = sd_bus_message_enter_container(reply, 'e', "sa{sas}");
+ if (r <= 0)
+ {
+ break;
+ } // e denotes 'dict entry'
+ const char* p; // path
+ r = sd_bus_message_read_basic(reply, 's', &p);
+ if (r <= 0)
+ break;
+ r = sd_bus_message_enter_container(reply, 'a', "{sas}");
+ if (r <= 0)
+ {
+ assert(0);
+ }
+ while (true)
+ {
+ const char* service; // service
+ r = sd_bus_message_enter_container(reply, 'e', "sas");
+ if (r <= 0)
+ {
+ break;
+ }
+ r = sd_bus_message_read_basic(reply, 's', &service);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ services_and_objects.emplace_back(std::string(service),
+ std::string(p));
+ r = sd_bus_message_enter_container(reply, 'a', "s");
+ if (r <= 0)
+ {
+ assert(0);
+ }
+ while (true)
+ {
+ const char* iface;
+ r = sd_bus_message_read_basic(reply, 's', &iface);
+ if (r <= 0)
+ {
+ break;
+ }
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit a
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit e
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit a
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit e
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit a
+
+ idx = 0;
+ N = services_and_objects.size();
+ for (const std::pair<std::string, std::string>& serv_and_obj :
+ services_and_objects)
+ {
+ if (idx % 100 == 99 || idx == N - 1)
+ {
+ g_footer_view->SetStatusString(
+ "6. Find Associations of Endpoints " + std::to_string(idx + 1) +
+ "/" + std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
+ ++idx;
+ err = SD_BUS_ERROR_NULL;
+ r = sd_bus_message_new_method_call(
+ bus, &m, serv_and_obj.first.c_str(), serv_and_obj.second.c_str(),
+ "org.freedesktop.DBus.Properties", "Get");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(
+ m, 's', "xyz.openbmc_project.Association.Definitions");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_append_basic(m, 's', "Associations");
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_call(bus, m, 0, &err, &reply);
+ if (r <= 0)
+ {
+ continue;
+ }
+ sig = sd_bus_message_get_signature(reply, 0);
+ if (strcmp(sig, "v"))
+ {
+ assert(0);
+ }
+ r = sd_bus_message_enter_container(reply, 'v', "a(sss)");
+ if (r <= 0)
+ {
+ continue;
+ }
+ r = sd_bus_message_enter_container(reply, 'a', "(sss)");
+ if (r <= 0)
+ {
+ continue;
+ }
+ while (true)
+ {
+ r = sd_bus_message_enter_container(reply, 'r', "sss");
+ if (r <= 0)
+ {
+ break;
+ } // struct
+ const char *forward, *reverse, *endpoint;
+ r = sd_bus_message_read_basic(reply, 's', &forward);
+ if (r < 0)
+ {
+ break;
+ }
+ r = sd_bus_message_read_basic(reply, 's', &reverse);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ r = sd_bus_message_read_basic(reply, 's', &endpoint);
+ if (r < 0)
+ {
+ assert(0);
+ }
+ (*sensor_snapshot)
+ ->AddAssociationDefinition(
+ serv_and_obj.second, std::string(forward),
+ std::string(reverse), std::string(endpoint));
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit struct
+ }
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit a
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ {
+ assert(0);
+ } // exit v
+ }
+
+ g_footer_view->SetStatusString("7. Check HWMon DBus objects");
+ DBusTopUpdateFooterView();
+ for (size_t i = 0; i < comms.size(); i++)
+ {
+ if (i % 100 == 99 || i == N - 1)
+ {
+ g_footer_view->SetStatusString("7. Check HWMon DBus objects " +
+ std::to_string(i + 1) + "/" +
+ std::to_string(N));
+ DBusTopUpdateFooterView();
+ }
const std::string& comm = comms[i];
const std::string& service = services[i];
if (comm.find("phosphor-hwmon-readd") != std::string::npos &&
@@ -431,53 +797,19 @@
{
// printf("Should introspect %s\n", service.c_str());
std::vector<std::string> objpaths =
- FindAllObjectPathsForService(service, nullptr);
+ FindAllObjectPathsForService(bus, service, nullptr);
for (const std::string& op : objpaths)
{
if (IsSensorObjectPath(op))
{
- g_sensor_snapshot->SetSensorVisibleFromHwmon(service, op);
+ (*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();
+
+ g_footer_view->SetStatusString("DBus object scan complete");
+ DBusTopUpdateFooterView();
}
} // namespace dbus_top_analyzer