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
on_loop(boost::asio::steady_timer * timer,const boost::system::error_code & error)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
main(int argc,const char ** argv)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_t> 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_t &>(*connection), expr,
108 [](sdbusplus::message_t &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 }