1#include <fcntl.h>
2#include <port/unistd.h>
3#include <stdlib.h>
4#include <time.h>
5#include <iostream>
6#include <iomanip>
7#include <vector>
8#include <random>
9#include <pcg_random.hpp>
10#include <IO/ReadHelpers.h>
11#include <Poco/Exception.h>
12#include <Common/Exception.h>
13#include <Common/randomSeed.h>
14#include <Common/ThreadPool.h>
15#include <Common/Stopwatch.h>
16#include <IO/BufferWithOwnMemory.h>
17#include <cstdlib>
18#include <port/clock.h>
19
20namespace DB
21{
22 namespace ErrorCodes
23 {
24 extern const int CANNOT_OPEN_FILE;
25 extern const int CANNOT_CLOSE_FILE;
26 extern const int CANNOT_READ_FROM_FILE_DESCRIPTOR;
27 extern const int CANNOT_WRITE_TO_FILE_DESCRIPTOR;
28 }
29}
30
31
32enum Mode
33{
34 MODE_NONE = 0,
35 MODE_READ = 1,
36 MODE_WRITE = 2,
37 MODE_ALIGNED = 4,
38 MODE_DIRECT = 8,
39 MODE_SYNC = 16,
40};
41
42
43void thread(int fd, int mode, size_t min_offset, size_t max_offset, size_t block_size, size_t count)
44{
45 using namespace DB;
46
47 Memory<> direct_buf(block_size, sysconf(_SC_PAGESIZE));
48 std::vector<char> simple_buf(block_size);
49
50 char * buf;
51 if ((mode & MODE_DIRECT))
52 buf = direct_buf.data();
53 else
54 buf = &simple_buf[0];
55
56 pcg64 rng(randomSeed());
57
58 for (size_t i = 0; i < count; ++i)
59 {
60 long rand_result1 = rng();
61 long rand_result2 = rng();
62 long rand_result3 = rng();
63
64 size_t rand_result = rand_result1 ^ (rand_result2 << 22) ^ (rand_result3 << 43);
65 size_t offset;
66 if ((mode & MODE_DIRECT) || (mode & MODE_ALIGNED))
67 offset = min_offset + rand_result % ((max_offset - min_offset) / block_size) * block_size;
68 else
69 offset = min_offset + rand_result % (max_offset - min_offset - block_size + 1);
70
71 if (mode & MODE_READ)
72 {
73 if (static_cast<int>(block_size) != pread(fd, buf, block_size, offset))
74 throwFromErrno("Cannot read", ErrorCodes::CANNOT_READ_FROM_FILE_DESCRIPTOR);
75 }
76 else
77 {
78 if (static_cast<int>(block_size) != pwrite(fd, buf, block_size, offset))
79 throwFromErrno("Cannot write", ErrorCodes::CANNOT_WRITE_TO_FILE_DESCRIPTOR);
80 }
81 }
82}
83
84
85int mainImpl(int argc, char ** argv)
86{
87 using namespace DB;
88
89 const char * file_name = 0;
90 int mode = MODE_NONE;
91 UInt64 min_offset = 0;
92 UInt64 max_offset = 0;
93 UInt64 block_size = 0;
94 UInt64 threads = 0;
95 UInt64 count = 0;
96
97 if (argc != 8)
98 {
99 std::cerr << "Usage: " << argv[0] << " file_name (r|w)[a][d][s] min_offset max_offset block_size threads count" << std::endl <<
100 "a - aligned, d - direct, s - sync" << std::endl;
101 return 1;
102 }
103
104 file_name = argv[1];
105 min_offset = parse<UInt64>(argv[3]);
106 max_offset = parse<UInt64>(argv[4]);
107 block_size = parse<UInt64>(argv[5]);
108 threads = parse<UInt64>(argv[6]);
109 count = parse<UInt64>(argv[7]);
110
111 for (int i = 0; argv[2][i]; ++i)
112 {
113 char c = argv[2][i];
114 switch(c)
115 {
116 case 'r':
117 mode |= MODE_READ;
118 break;
119 case 'w':
120 mode |= MODE_WRITE;
121 break;
122 case 'a':
123 mode |= MODE_ALIGNED;
124 break;
125 case 'd':
126 mode |= MODE_DIRECT;
127 break;
128 case 's':
129 mode |= MODE_SYNC;
130 break;
131 default:
132 throw Poco::Exception("Invalid mode");
133 }
134 }
135
136 ThreadPool pool(threads);
137
138 #ifndef __APPLE__
139 int fd = open(file_name, ((mode & MODE_READ) ? O_RDONLY : O_WRONLY) | ((mode & MODE_DIRECT) ? O_DIRECT : 0) | ((mode & MODE_SYNC) ? O_SYNC : 0));
140 #else
141 int fd = open(file_name, ((mode & MODE_READ) ? O_RDONLY : O_WRONLY) | ((mode & MODE_SYNC) ? O_SYNC : 0));
142 #endif
143 if (-1 == fd)
144 throwFromErrno("Cannot open file", ErrorCodes::CANNOT_OPEN_FILE);
145 #ifdef __APPLE__
146 if (mode & MODE_DIRECT)
147 if (fcntl(fd, F_NOCACHE, 1) == -1)
148 throwFromErrno("Cannot open file", ErrorCodes::CANNOT_CLOSE_FILE);
149 #endif
150 Stopwatch watch;
151
152 for (size_t i = 0; i < threads; ++i)
153 pool.scheduleOrThrowOnError(std::bind(thread, fd, mode, min_offset, max_offset, block_size, count));
154 pool.wait();
155
156 fsync(fd);
157
158 watch.stop();
159
160 if (0 != close(fd))
161 throwFromErrno("Cannot close file", ErrorCodes::CANNOT_CLOSE_FILE);
162
163 std::cout << std::fixed << std::setprecision(2)
164 << "Done " << count << " * " << threads << " ops";
165 if (mode & MODE_ALIGNED)
166 std::cout << " (aligned)";
167 if (mode & MODE_DIRECT)
168 std::cout << " (direct)";
169 if (mode & MODE_SYNC)
170 std::cout << " (sync)";
171 std::cout << " in " << watch.elapsedSeconds() << " sec."
172 << ", " << count * threads / watch.elapsedSeconds() << " ops/sec."
173 << ", " << count * threads * block_size / watch.elapsedSeconds() / 1000000 << " MB/sec."
174 << std::endl;
175
176 return 0;
177}
178
179
180int main(int argc, char ** argv)
181{
182 try
183 {
184 return mainImpl(argc, argv);
185 }
186 catch (const Poco::Exception & e)
187 {
188 std::cerr << e.what() << ", " << e.message() << std::endl;
189 return 1;
190 }
191}
192