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 }