blob: 008ed5ecb2bf69e03e00daa6bc3274b0ff33f1ae [file] [log] [blame]
Austin Schuhe6b2b882023-02-04 11:42:40 -08001#include <fcntl.h>
James Kuszmaul4b208072023-05-03 09:39:32 -05002#include <sys/resource.h>
Austin Schuhe6b2b882023-02-04 11:42:40 -08003#include <sys/stat.h>
4#include <sys/types.h>
Austin Schuhf97b4632023-02-11 16:52:58 -08005#include <sys/uio.h>
Austin Schuhe6b2b882023-02-04 11:42:40 -08006
7#include <chrono>
Brennan Coslett7a8533f2023-04-13 13:08:17 -05008#include <csignal>
9#include <filesystem>
Austin Schuhe6b2b882023-02-04 11:42:40 -080010
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "gflags/gflags.h"
12#include "glog/logging.h"
13
Brennan Coslett7a8533f2023-04-13 13:08:17 -050014#include "aos/containers/resizeable_buffer.h"
Austin Schuhe6b2b882023-02-04 11:42:40 -080015#include "aos/init.h"
16#include "aos/realtime.h"
17#include "aos/time/time.h"
Austin Schuhe6b2b882023-02-04 11:42:40 -080018
19namespace chrono = std::chrono;
20
21DEFINE_string(file, "/media/sda1/foo", "File to write to.");
22
23DEFINE_uint32(write_size, 4096, "Size of hunk to write");
Brennan Coslett7a8533f2023-04-13 13:08:17 -050024DEFINE_bool(cleanup, true, "If true, delete the created file");
James Kuszmaul4b208072023-05-03 09:39:32 -050025DEFINE_int32(nice, -20,
26 "Priority to nice to. Set to 0 to not change the priority.");
Austin Schuhe6b2b882023-02-04 11:42:40 -080027DEFINE_bool(sync, false, "If true, sync the file after each written block.");
Austin Schuhf97b4632023-02-11 16:52:58 -080028DEFINE_bool(writev, false, "If true, use writev.");
Austin Schuhe6b2b882023-02-04 11:42:40 -080029DEFINE_bool(direct, false, "If true, O_DIRECT.");
Austin Schuhf97b4632023-02-11 16:52:58 -080030DEFINE_uint32(chunks, 1, "Chunks to write using writev.");
31DEFINE_uint32(chunk_size, 512, "Chunk size to write using writev.");
Austin Schuh6049d342023-06-01 12:20:51 -070032DEFINE_uint64(overall_size, 0,
33 "If nonzero, write this many bytes and then stop. Must be a "
34 "multiple of --write_size");
Austin Schuhe6b2b882023-02-04 11:42:40 -080035
Brennan Coslett7a8533f2023-04-13 13:08:17 -050036// Stolen from aos/events/logging/DummyEncoder
37class AlignedReallocator {
38 public:
39 static void *Realloc(void *old, size_t old_size, size_t new_capacity) {
40 void *new_memory = std::aligned_alloc(512, new_capacity);
41 if (old) {
42 memcpy(new_memory, old, old_size);
43 free(old);
44 }
45 return new_memory;
46 }
47};
48
49void trap_sig(int signum) { exit(signum); }
50
Austin Schuh6049d342023-06-01 12:20:51 -070051aos::monotonic_clock::time_point start_time = aos::monotonic_clock::min_time;
52std::atomic<size_t> written_data = 0;
53
Brennan Coslett7a8533f2023-04-13 13:08:17 -050054void cleanup() {
Austin Schuh6049d342023-06-01 12:20:51 -070055 LOG(INFO) << "Overall average write speed: "
56 << ((written_data) /
57 chrono::duration<double>(aos::monotonic_clock::now() -
58 start_time)
59 .count() /
60 1024. / 1024.)
61 << " MB/s for " << static_cast<double>(written_data) / 1024. / 1024.
62 << "MB";
63
Brennan Coslett7a8533f2023-04-13 13:08:17 -050064 // Delete FLAGS_file at shutdown
65 PCHECK(std::filesystem::remove(FLAGS_file) != 0) << "Failed to cleanup file";
66}
67
Philipp Schrader790cb542023-07-05 21:06:52 -070068int main(int argc, char **argv) {
Austin Schuhe6b2b882023-02-04 11:42:40 -080069 aos::InitGoogle(&argc, &argv);
Brennan Coslett7a8533f2023-04-13 13:08:17 -050070 // c++ needs bash's trap <fcn> EXIT
71 // instead we get this mess :(
72 if (FLAGS_cleanup) {
73 std::signal(SIGINT, trap_sig);
74 std::signal(SIGTERM, trap_sig);
75 std::signal(SIGKILL, trap_sig);
76 std::signal(SIGHUP, trap_sig);
77 std::atexit(cleanup);
78 }
79 aos::AllocatorResizeableBuffer<AlignedReallocator> data;
Austin Schuhe6b2b882023-02-04 11:42:40 -080080
Austin Schuhe6b2b882023-02-04 11:42:40 -080081 {
Brennan Coslett7a8533f2023-04-13 13:08:17 -050082 // We want uncompressible data. The easiest way to do this is to grab a
83 // good sized block from /dev/random, and then reuse it.
Austin Schuhe6b2b882023-02-04 11:42:40 -080084 int random_fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
85 PCHECK(random_fd != -1) << ": Failed to open /dev/random";
86 data.resize(FLAGS_write_size);
87 size_t written = 0;
88 while (written < data.size()) {
89 const size_t result =
90 read(random_fd, data.data() + written, data.size() - written);
91 PCHECK(result > 0);
92 written += result;
93 }
94
95 PCHECK(close(random_fd) == 0);
96 }
97
Austin Schuhf97b4632023-02-11 16:52:58 -080098 std::vector<struct iovec> iovec;
Brennan Coslett7a8533f2023-04-13 13:08:17 -050099 if (FLAGS_writev) {
100 iovec.resize(FLAGS_chunks);
101 CHECK_LE(FLAGS_chunks * FLAGS_chunk_size, FLAGS_write_size);
Austin Schuhf97b4632023-02-11 16:52:58 -0800102
Brennan Coslett7a8533f2023-04-13 13:08:17 -0500103 for (size_t i = 0; i < FLAGS_chunks; ++i) {
104 iovec[i].iov_base = &data.at(i * FLAGS_chunk_size);
105 iovec[i].iov_len = FLAGS_chunk_size;
106 }
107 iovec[FLAGS_chunks - 1].iov_base =
108 &data.at((FLAGS_chunks - 1) * FLAGS_chunk_size);
109 iovec[FLAGS_chunks - 1].iov_len =
110 data.size() - (FLAGS_chunks - 1) * FLAGS_chunk_size;
Austin Schuhf97b4632023-02-11 16:52:58 -0800111 }
Austin Schuhf97b4632023-02-11 16:52:58 -0800112
Philipp Schrader790cb542023-07-05 21:06:52 -0700113 int fd =
114 open(FLAGS_file.c_str(),
115 O_RDWR | O_CLOEXEC | O_CREAT | (FLAGS_direct ? O_DIRECT : 0), 0774);
Austin Schuhe6b2b882023-02-04 11:42:40 -0800116 PCHECK(fd != -1);
117
Austin Schuh6049d342023-06-01 12:20:51 -0700118 start_time = aos::monotonic_clock::now();
Austin Schuhf97b4632023-02-11 16:52:58 -0800119 aos::monotonic_clock::time_point last_time = start_time;
Austin Schuhe6b2b882023-02-04 11:42:40 -0800120 size_t last_written_data = 0;
Austin Schuh6049d342023-06-01 12:20:51 -0700121 written_data = 0;
Austin Schuhe6b2b882023-02-04 11:42:40 -0800122
James Kuszmaul4b208072023-05-03 09:39:32 -0500123 if (FLAGS_nice != 0) {
124 PCHECK(-1 != setpriority(PRIO_PROCESS, 0, FLAGS_nice))
125 << ": Renicing to " << FLAGS_nice << " failed";
126 }
127
Austin Schuhe6b2b882023-02-04 11:42:40 -0800128 while (true) {
Austin Schuh6049d342023-06-01 12:20:51 -0700129 // Bail if we have written our limit.
130 if (written_data >= FLAGS_overall_size && FLAGS_overall_size != 0) {
131 break;
132 }
133
Austin Schuhf97b4632023-02-11 16:52:58 -0800134 if (FLAGS_writev) {
135 PCHECK(writev(fd, iovec.data(), iovec.size()) ==
136 static_cast<ssize_t>(data.size()))
137 << ": Failed after "
138 << chrono::duration<double>(aos::monotonic_clock::now() - start_time)
139 .count();
140 } else {
141 PCHECK(write(fd, data.data(), data.size()) ==
142 static_cast<ssize_t>(data.size()))
143 << ": Failed after "
144 << chrono::duration<double>(aos::monotonic_clock::now() - start_time)
145 .count();
146 }
Austin Schuhe6b2b882023-02-04 11:42:40 -0800147
148 // Trigger a flush if asked.
149 if (FLAGS_sync) {
150 const aos::monotonic_clock::time_point monotonic_now =
151 aos::monotonic_clock::now();
152 sync_file_range(fd, written_data, data.size(), SYNC_FILE_RANGE_WRITE);
153
154 // Now, blocking flush the previous page so we don't get too far ahead.
155 // This is Linus' recommendation.
156 if (written_data > 0) {
157 sync_file_range(fd, written_data - data.size(), data.size(),
158 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
159 SYNC_FILE_RANGE_WAIT_AFTER);
160 posix_fadvise(fd, written_data - data.size(), data.size(),
161 POSIX_FADV_DONTNEED);
162 }
163 VLOG(1) << "Took "
164 << chrono::duration<double>(aos::monotonic_clock::now() -
165 monotonic_now)
166 .count();
167 }
168
169 written_data += data.size();
170
171 const aos::monotonic_clock::time_point monotonic_now =
172 aos::monotonic_clock::now();
173 // Print out MB/s once it has been at least 1 second since last time.
174 if (monotonic_now > last_time + chrono::seconds(1)) {
175 LOG(INFO)
176 << ((written_data - last_written_data) /
177 chrono::duration<double>(monotonic_now - last_time).count() /
178 1024. / 1024.)
Austin Schuh6049d342023-06-01 12:20:51 -0700179 << " MB/s, average of "
180 << (written_data /
181 chrono::duration<double>(monotonic_now - start_time).count() /
182 1024. / 1024.)
183 << " MB/s for " << static_cast<double>(written_data) / 1024. / 1024.
184 << "MB";
Austin Schuhe6b2b882023-02-04 11:42:40 -0800185 last_time = monotonic_now;
186 last_written_data = written_data;
187 }
188 }
189
190 return 0;
191}