1 #include <CLI/App.hpp>
2 #include <CLI/Config.hpp>
3 #include <CLI/Formatter.hpp>
4 #include <boost/asio/steady_timer.hpp>
5 #include <chrono>
6 #include <functional>
7 #include <iostream>
8 #include <memory>
9 #include <sdbusplus/asio/connection.hpp>
10 #include <sdbusplus/asio/object_server.hpp>
11 
12 boost::asio::io_context io;
13 std::vector<std::shared_ptr<sdbusplus::asio::dbus_interface>> sensorInterfaces;
14 
15 int update_interval_seconds = 1;
16 
17 size_t reads = 0;
18 
19 void on_loop(boost::asio::steady_timer *timer,
20              const boost::system::error_code &error) {
21 
22   if (error) {
23     return;
24   }
25   std::chrono::steady_clock::time_point start =
26       std::chrono::steady_clock::now();
27 
28   static double value = -100.0;
29 
30   for (auto &sensor : sensorInterfaces) {
31     if (!sensor->set_property("Value", value)) {
32       std::cout << "Can't set property for sensor\n";
33     }
34     value += 10.0;
35     if (value >= 100.0) {
36       value = -100.0;
37     }
38   }
39   if (!sensorInterfaces.empty()) {
40     std::cout << sensorInterfaces.size() << " updates took "
41               << std::chrono::duration_cast<std::chrono::duration<float>>(
42                      std::chrono::steady_clock::now() - start)
43                      .count()
44               << " seconds\n";
45   }
46 
47   if (reads > 0) {
48     std::cout << "Read " << reads << " sensor updates\n";
49     reads = 0;
50   }
51 
52   timer->expires_from_now(std::chrono::seconds(update_interval_seconds));
53   timer->async_wait(std::bind_front(on_loop, timer));
54 };
55 
56 int main(int argc, const char **argv) {
57   CLI::App app{"dbus performance test application"};
58 
59   size_t number_of_sensors = 0;
60   app.add_option("-n", number_of_sensors, "Number of sensors to create");
61 
62   bool watch_sensor_updates = false;
63   app.add_flag("-w", watch_sensor_updates,
64                "Watch for all sensor values from dbus");
65   CLI11_PARSE(app, argc, argv);
66 
67   if (number_of_sensors == 0 && watch_sensor_updates == false) {
68     std::cout << "Nothing to do\n";
69     app.exit(CLI::CallForHelp());
70     return -1;
71   }
72 
73   std::shared_ptr<sdbusplus::asio::connection> connection =
74       std::make_shared<sdbusplus::asio::connection>(io);
75   sdbusplus::asio::object_server objectServer(connection);
76 
77   std::string name = "foobar";
78   sensorInterfaces.reserve(number_of_sensors);
79   for (size_t sensorIndex = 0; sensorIndex < number_of_sensors; sensorIndex++) {
80     sdbusplus::message::object_path path(
81         "/xyz/openbmc_project/sensors/temperature/");
82     path /= name + std::to_string(sensorIndex);
83     std::shared_ptr<sdbusplus::asio::dbus_interface> sensorInterface =
84         objectServer.add_interface(path.str,
85                                    "xyz.openbmc_project.Sensor.Value");
86     sensorInterface->register_property<std::string>(
87         "Unit", "xyz.openbmc_project.Sensor.Unit.DegreesC");
88     sensorInterface->register_property<double>("MaxValue", 100);
89     sensorInterface->register_property<double>("MinValue", -100);
90     sensorInterface->register_property<double>("Value", 42);
91 
92     sensorInterface->initialize();
93     sensorInterfaces.emplace_back(sensorInterface);
94   }
95 
96   std::cout << "Done initializing\n";
97 
98   boost::asio::steady_timer timer(io);
99   timer.expires_from_now(std::chrono::seconds(update_interval_seconds));
100   timer.async_wait(std::bind_front(on_loop, &timer));
101   std::optional<sdbusplus::bus::match::match> match;
102   if (watch_sensor_updates) {
103     std::string expr = "type='signal',member='PropertiesChanged',path_"
104                        "namespace='/xyz/openbmc_project/sensors'";
105 
106     match.emplace(
107         static_cast<sdbusplus::bus::bus &>(*connection), expr,
108         [](sdbusplus::message::message &message) {
109           std::string objectName;
110           std::vector<std::pair<std::string, std::variant<double>>> result;
111           try {
112             message.read(objectName, result);
113           } catch (const sdbusplus::exception_t &) {
114             std::cerr << "Error reading match data\n";
115             return;
116           }
117           for (auto &property : result) {
118             if (property.first == "Value") {
119               reads++;
120             }
121           }
122         });
123   }
124 
125   io.run();
126 
127   return 0;
128 }