Add mode to ssd_profiler to simulate logger
When --rate_limit is specified, write every 100ms like the logger does.
--write_bandwidth can be used to specify the effective write rate in
MB/s.
Change-Id: Ib6a0d4fec249ad1d559caf80a0f352565c8e3832
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/y2023/ssd_profiler.cc b/y2023/ssd_profiler.cc
index 008ed5e..e7493ff 100644
--- a/y2023/ssd_profiler.cc
+++ b/y2023/ssd_profiler.cc
@@ -32,6 +32,12 @@
DEFINE_uint64(overall_size, 0,
"If nonzero, write this many bytes and then stop. Must be a "
"multiple of --write_size");
+DEFINE_bool(rate_limit, false,
+ "If true, kick off writes every 100ms to mimic logger write "
+ "patterns more correctly.");
+DEFINE_double(write_bandwidth, 120.0,
+ "Write speed in MB/s to simulate. This is only used when "
+ "--rate_limit is specified.");
// Stolen from aos/events/logging/DummyEncoder
class AlignedReallocator {
@@ -116,9 +122,19 @@
PCHECK(fd != -1);
start_time = aos::monotonic_clock::now();
- aos::monotonic_clock::time_point last_time = start_time;
+ aos::monotonic_clock::time_point last_print_time = start_time;
+ aos::monotonic_clock::time_point cycle_start_time = start_time;
size_t last_written_data = 0;
written_data = 0;
+ // Track how much data we write per cycle. When --rate_limit is specified,
+ // --write_bandwidth is the amount of data we want to write per second, and we
+ // want to write it in cycles of 100ms to simulate the logger.
+ size_t cycle_written_data = 0;
+ size_t data_per_cycle = std::numeric_limits<size_t>::max();
+ if (FLAGS_rate_limit) {
+ data_per_cycle =
+ static_cast<size_t>((FLAGS_write_bandwidth * 1024 * 1024) / 10);
+ }
if (FLAGS_nice != 0) {
PCHECK(-1 != setpriority(PRIO_PROCESS, 0, FLAGS_nice))
@@ -167,14 +183,52 @@
}
written_data += data.size();
+ cycle_written_data += data.size();
+
+ // Simulate the logger by writing the specified amount of data in periods of
+ // 100ms.
+ bool reset_cycle = false;
+ if (cycle_written_data > data_per_cycle && FLAGS_rate_limit) {
+ // Check how much data we should have already written based on
+ // --write_bandwidth.
+ const size_t current_target =
+ FLAGS_write_bandwidth * 1024 * 1024 *
+ chrono::duration<double>(aos::monotonic_clock::now() - start_time)
+ .count();
+ const bool caught_up = written_data > current_target;
+ if (caught_up) {
+ // If we're on track, sleep for the rest of this cycle, as long as we
+ // didn't use up all the cycle time writing.
+ const aos::monotonic_clock::time_point monotonic_now =
+ aos::monotonic_clock::now();
+ const auto sleep_duration =
+ (cycle_start_time + chrono::milliseconds(100)) - monotonic_now;
+ if (sleep_duration.count() > 0) {
+ VLOG(2) << "Sleeping for " << sleep_duration.count();
+ std::this_thread::sleep_for(sleep_duration);
+ } else {
+ LOG(WARNING) << "It took longer than 100ms to write "
+ << data_per_cycle << " bytes.";
+ }
+ reset_cycle = true;
+ } else {
+ // If we aren't on track, don't sleep.
+ LOG(WARNING) << "Still catching up to target write rate.";
+ }
+ // Either way, reset the data we're counting for this "cycle". If we're
+ // still behind, let's check again after writing another data_per_cycle
+ // bytes.
+ cycle_written_data = 0;
+ }
const aos::monotonic_clock::time_point monotonic_now =
aos::monotonic_clock::now();
// Print out MB/s once it has been at least 1 second since last time.
- if (monotonic_now > last_time + chrono::seconds(1)) {
+ if (monotonic_now > last_print_time + chrono::seconds(1)) {
LOG(INFO)
<< ((written_data - last_written_data) /
- chrono::duration<double>(monotonic_now - last_time).count() /
+ chrono::duration<double>(monotonic_now - last_print_time)
+ .count() /
1024. / 1024.)
<< " MB/s, average of "
<< (written_data /
@@ -182,9 +236,16 @@
1024. / 1024.)
<< " MB/s for " << static_cast<double>(written_data) / 1024. / 1024.
<< "MB";
- last_time = monotonic_now;
+ last_print_time = monotonic_now;
last_written_data = written_data;
}
+
+ // Do this at the end so that we're setting the next cycle start time as
+ // accurately as possible.
+ if (reset_cycle) {
+ cycle_start_time = monotonic_now;
+ VLOG(1) << cycle_start_time;
+ }
}
return 0;