--- /dev/null
+#include <gio/gio.h>
+#include "sessiond.h"
+
+#include <cstdlib>
+#include <chrono>
+#include <iostream>
+#include <thread>
+
+using namespace std::literals;
+
+// tweakables
+static constexpr size_t CALLS_TO_MAKE = 10;
+static constexpr auto SUBSESSION_NAME = "benchmark"sv;
+static constexpr int UID = 5001;
+static constexpr int IMAGE_SIZE = 10 * 1024;
+
+using Clock = std::chrono::high_resolution_clock;
+using Timestamp = Clock::time_point;
+using Duration = Clock::duration;
+
+/* sessiond API mandates the use of GLib, this is just a test so use
+ * globals to avoid all that userdata pointer management nonsense */
+static GMainLoop *mainloop = nullptr;
+static bool waiting_for_reply = false;
+std::chrono::duration <double, std::milli> total_duration;
+static Timestamp start_timestamp;
+static auto calls_remaining = CALLS_TO_MAKE;
+static std::chrono::seconds sleep_duration;
+
+void callback(int result, void *userdata)
+{
+ total_duration += Clock::now() - start_timestamp;
+ if (result != SUBSESSION_ERROR_NONE) {
+ std::cout << "ERROR! Code: " << result << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ -- calls_remaining;
+ waiting_for_reply = false;
+}
+
+gboolean periodic_check (gpointer data)
+{
+ if (waiting_for_reply) {
+ std::this_thread::yield();
+ return TRUE;
+ }
+
+ if (!calls_remaining) {
+ g_main_loop_quit(mainloop);
+ return TRUE;
+ }
+
+ waiting_for_reply = true;
+ subsession_remove_user(UID, SUBSESSION_NAME.data(), nullptr, nullptr);
+ std::this_thread::sleep_for(sleep_duration);
+ start_timestamp = Clock::now();
+ subsession_add_user_fixed_size(UID, SUBSESSION_NAME.data(), IMAGE_SIZE, callback, nullptr);
+ return TRUE;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ std::cout << "usage: benchmark <seconds_to_sleep>" << std::endl;
+ return EXIT_FAILURE;
+ }
+ sleep_duration = std::chrono::seconds(std::stoi(argv[1]));
+ total_duration = total_duration.zero();
+
+ // cleanup any remnant garbage from earlier failed tests
+ subsession_remove_user(UID, SUBSESSION_NAME.data(), nullptr, nullptr);
+
+ const auto idle_id = g_idle_add(periodic_check, nullptr);
+ mainloop = g_main_loop_new(nullptr, false);
+ g_main_loop_run(mainloop);
+
+ std::cout << "Waited an average of " << total_duration.count() / CALLS_TO_MAKE << "ms per subsession add" << std::endl;
+
+ g_source_remove(idle_id);
+ g_main_loop_unref(mainloop);
+
+ return EXIT_SUCCESS;
+}