#include <seastar/json/formatter.hh>
#include <seastar/util/later.hh>
#include <seastar/testing/random.hh>
+#include <seastar/core/memory.hh>
+#include <seastar/core/reactor.hh>
#include <signal.h>
+#if FMT_VERSION >= 90000
+namespace perf_tests::internal {
+ struct duration;
+}
+template <> struct fmt::formatter<perf_tests::internal::duration> : fmt::ostream_formatter {};
+#endif
+
namespace perf_tests {
namespace internal {
}
+uint64_t perf_stats::perf_mallocs() {
+ return memory::stats().mallocs();
+}
+
+uint64_t perf_stats::perf_tasks_processed() {
+ return engine().get_sched_stats().tasks_processed;
+}
+
+perf_stats perf_stats::snapshot(linux_perf_event* instructions_retired_counter) {
+ return perf_stats(
+ perf_mallocs(),
+ perf_tasks_processed(),
+ instructions_retired_counter ? instructions_retired_counter->read() : 0
+ );
+}
+
time_measurement measure_time;
struct config;
};
struct result {
- sstring test_name;
+ sstring test_name = "";
- uint64_t total_iterations;
- unsigned runs;
+ uint64_t total_iterations = 0;
+ unsigned runs = 0;
- double median;
- double mad;
- double min;
- double max;
+ double median = 0.;
+ double mad = 0.;
+ double min = 0.;
+ double max = 0.;
+
+ double allocs = 0.;
+ double tasks = 0.;
+ double inst = 0.;
};
-namespace {
struct duration {
double value;
return os;
}
-}
-
-static constexpr auto format_string = "{:<40} {:>11} {:>11} {:>11} {:>11} {:>11}\n";
+static constexpr auto header_format_string = "{:<40} {:>11} {:>11} {:>11} {:>11} {:>11} {:>11} {:>11} {:>11}\n";
+static constexpr auto format_string = "{:<40} {:>11} {:>11} {:>11} {:>11} {:>11} {:>11.3f} {:>11.3f} {:>11.1f}\n";
struct stdout_printer final : result_printer {
virtual void print_configuration(const config& c) override {
"number of runs:", c.number_of_runs,
"number of cores:", smp::count,
"random seed:", c.random_seed);
- fmt::print(format_string, "test", "iterations", "median", "mad", "min", "max");
+ fmt::print(header_format_string, "test", "iterations", "median", "mad", "min", "max", "allocs", "tasks", "inst");
}
virtual void print_result(const result& r) override {
fmt::print(format_string, r.test_name, r.total_iterations / r.runs, duration { r.median },
- duration { r.mad }, duration { r.min }, duration { r.max });
+ duration { r.mad }, duration { r.min }, duration { r.max },
+ r.allocs, r.tasks, r.inst);
}
};
result["mad"] = r.mad;
result["min"] = r.min;
result["max"] = r.max;
+ result["allocs"] = r.allocs;
+ result["tasks"] = r.tasks;
+ result["inst"] = r.inst;
}
};
// dry run, estimate the number of iterations
if (conf.single_run_duration.count()) {
// switch out of seastar thread
- later().then([&] {
+ yield().then([&] {
tmr.arm(conf.single_run_duration);
return do_single_run().finally([&] {
tmr.cancel();
}).get();
}
+ result r{};
+
auto results = std::vector<double>(conf.number_of_runs);
uint64_t total_iterations = 0;
for (auto i = 0u; i < conf.number_of_runs; i++) {
// switch out of seastar thread
- later().then([&] {
+ yield().then([&] {
_single_run_iterations = 0;
- return do_single_run().then([&] (clock_type::duration dt) {
+ return do_single_run().then([&] (run_result rr) {
+ clock_type::duration dt = rr.duration;
double ns = std::chrono::duration_cast<std::chrono::nanoseconds>(dt).count();
results[i] = ns / _single_run_iterations;
total_iterations += _single_run_iterations;
+
+ r.allocs += double(rr.stats.allocations) / _single_run_iterations;
+ r.tasks += double(rr.stats.tasks_executed) / _single_run_iterations;
+ r.inst += double(rr.stats.instructions_retired) / _single_run_iterations;
});
}).get();
}
- result r{};
r.test_name = name();
r.total_iterations = total_iterations;
r.runs = conf.number_of_runs;
r.min = results[0];
r.max = results[results.size() - 1];
+ r.allocs /= conf.number_of_runs;
+ r.tasks /= conf.number_of_runs;
+ r.inst /= conf.number_of_runs;
+
for (auto& rp : conf.printers) {
rp->print_result(r);
}