1
1
#include < chrono>
2
+ #include < exception>
2
3
#include < iostream>
3
4
#include < memory>
4
5
#include < mutex> // NOLINT
5
6
#include < random>
6
7
#include < sstream>
7
8
#include < string>
8
9
#include < thread>
10
+ #include < unordered_map>
9
11
#include < vector>
10
12
11
13
#include < cpp_random_distributions/zipfian_int_distribution.h>
@@ -29,12 +31,6 @@ auto ClockMs() -> uint64_t {
29
31
return static_cast <uint64_t >(tm.tv_sec * 1000 ) + static_cast <uint64_t >(tm.tv_usec / 1000 );
30
32
}
31
33
32
- static const size_t BUSTUB_SCAN_THREAD = 8 ;
33
- static const size_t BUSTUB_GET_THREAD = 8 ;
34
- static const size_t LRU_K_SIZE = 16 ;
35
- static const size_t BUSTUB_PAGE_CNT = 6400 ;
36
- static const size_t BUSTUB_BPM_SIZE = 64 ;
37
-
38
34
struct BpmTotalMetrics {
39
35
uint64_t scan_cnt_{0 };
40
36
uint64_t get_cnt_{0 };
@@ -100,6 +96,45 @@ struct BpmMetrics {
100
96
}
101
97
};
102
98
99
+ struct BustubBenchPageHeader {
100
+ uint64_t seed_;
101
+ uint64_t page_id_;
102
+ char data_[0 ];
103
+ };
104
+
105
+ // / Modify the page and save some data inside
106
+ auto ModifyPage (char *data, size_t page_idx, uint64_t seed) -> void {
107
+ auto *pg = reinterpret_cast <BustubBenchPageHeader *>(data);
108
+ pg->seed_ = seed;
109
+ pg->page_id_ = page_idx;
110
+ pg->data_ [pg->seed_ % 4000 ] = pg->seed_ % 256 ;
111
+ }
112
+
113
+ // / Check the page and verify the data inside
114
+ auto CheckPageConsistentNoSeed (const char *data, size_t page_idx) -> void {
115
+ const auto *pg = reinterpret_cast <const BustubBenchPageHeader *>(data);
116
+ if (pg->page_id_ != page_idx) {
117
+ fmt::println (stderr, " page header not consistent: page_id_={} page_idx={}" , pg->page_id_ , page_idx);
118
+ std::terminate ();
119
+ }
120
+ auto left = static_cast <unsigned int >(static_cast <unsigned char >(pg->data_ [pg->seed_ % 4000 ]));
121
+ auto right = static_cast <unsigned int >(pg->seed_ % 256 );
122
+ if (left != right) {
123
+ fmt::println (stderr, " page content not consistent: data_[{}]={} seed_ % 256={}" , pg->seed_ % 4000 , left, right);
124
+ std::terminate ();
125
+ }
126
+ }
127
+
128
+ // / Check the page and verify the data inside
129
+ auto CheckPageConsistent (const char *data, size_t page_idx, uint64_t seed) -> void {
130
+ const auto *pg = reinterpret_cast <const BustubBenchPageHeader *>(data);
131
+ if (pg->seed_ != seed) {
132
+ fmt::println (stderr, " page seed not consistent: seed_={} seed={}" , pg->seed_ , seed);
133
+ std::terminate ();
134
+ }
135
+ CheckPageConsistentNoSeed (data, page_idx);
136
+ }
137
+
103
138
// NOLINTNEXTLINE
104
139
auto main (int argc, char **argv) -> int {
105
140
using bustub::AccessType;
@@ -109,7 +144,12 @@ auto main(int argc, char **argv) -> int {
109
144
110
145
argparse::ArgumentParser program (" bustub-bpm-bench" );
111
146
program.add_argument (" --duration" ).help (" run bpm bench for n milliseconds" );
112
- program.add_argument (" --latency" ).help (" set disk latency to n milliseconds" );
147
+ program.add_argument (" --latency" ).help (" enable disk latency" );
148
+ program.add_argument (" --scan-thread-n" ).help (" number of scan threads" );
149
+ program.add_argument (" --get-thread-n" ).help (" number of lookup threads" );
150
+ program.add_argument (" --bpm-size" ).help (" buffer pool size" );
151
+ program.add_argument (" --db-size" ).help (" number of pages" );
152
+ program.add_argument (" --lru-k-size" ).help (" lru-k size" );
113
153
114
154
try {
115
155
program.parse_args (argc, argv);
@@ -124,102 +164,133 @@ auto main(int argc, char **argv) -> int {
124
164
duration_ms = std::stoi (program.get (" --duration" ));
125
165
}
126
166
127
- uint64_t latency_ms = 0 ;
167
+ uint64_t enable_latency = 0 ;
128
168
if (program.present (" --latency" )) {
129
- latency_ms = std::stoi (program.get (" --latency" ));
169
+ enable_latency = std::stoi (program.get (" --latency" ));
170
+ }
171
+
172
+ uint64_t scan_thread_n = 8 ;
173
+ if (program.present (" --scan-thread-n" )) {
174
+ scan_thread_n = std::stoi (program.get (" --scan-thread-n" ));
175
+ }
176
+
177
+ uint64_t get_thread_n = 8 ;
178
+ if (program.present (" --get-thread-n" )) {
179
+ get_thread_n = std::stoi (program.get (" --get-thread-n" ));
180
+ }
181
+
182
+ uint64_t bustub_page_cnt = 6400 ;
183
+ if (program.present (" --db-size" )) {
184
+ bustub_page_cnt = std::stoi (program.get (" --db-size" ));
185
+ }
186
+
187
+ uint64_t bustub_bpm_size = 64 ;
188
+ if (program.present (" --bpm-size" )) {
189
+ bustub_bpm_size = std::stoi (program.get (" --bpm-size" ));
190
+ }
191
+
192
+ uint64_t lru_k_size = 16 ;
193
+ if (program.present (" --lru-k-size" )) {
194
+ bustub_page_cnt = std::stoi (program.get (" --lru-k-size" ));
130
195
}
131
196
132
197
auto disk_manager = std::make_unique<DiskManagerUnlimitedMemory>();
133
- auto bpm = std::make_unique<BufferPoolManager>(BUSTUB_BPM_SIZE , disk_manager.get (), LRU_K_SIZE );
198
+ auto bpm = std::make_unique<BufferPoolManager>(bustub_bpm_size , disk_manager.get (), lru_k_size );
134
199
std::vector<page_id_t > page_ids;
135
200
136
- fmt::print (stderr, " [info] total_page={}, duration_ms={}, latency_ms={}, lru_k_size={}, bpm_size={}\n " ,
137
- BUSTUB_PAGE_CNT, duration_ms, latency_ms, LRU_K_SIZE, BUSTUB_BPM_SIZE);
201
+ fmt::print (stderr,
202
+ " [info] total_page={}, duration_ms={}, latency={}, lru_k_size={}, bpm_size={}, scan_thread_cnt={}, "
203
+ " get_thread_cnt={}\n " ,
204
+ bustub_page_cnt, duration_ms, enable_latency, lru_k_size, bustub_bpm_size, scan_thread_n, get_thread_n);
138
205
139
- for (size_t i = 0 ; i < BUSTUB_PAGE_CNT ; i++) {
206
+ for (size_t i = 0 ; i < bustub_page_cnt ; i++) {
140
207
page_id_t page_id;
141
208
auto *page = bpm->NewPage (&page_id);
142
209
if (page == nullptr ) {
143
210
throw std::runtime_error (" new page failed" );
144
211
}
145
- char &ch = page-> GetData ()[i % 1024 ];
146
- ch = 1 ;
212
+
213
+ ModifyPage (page-> GetData (), i, 0 ) ;
147
214
148
215
bpm->UnpinPage (page_id, true );
149
216
page_ids.push_back (page_id);
150
217
}
151
218
152
219
// enable disk latency after creating all pages
153
- disk_manager->SetLatency (latency_ms );
220
+ disk_manager->EnableLatencySimulator (enable_latency != 0 );
154
221
155
222
fmt::print (stderr, " [info] benchmark start\n " );
156
223
157
224
BpmTotalMetrics total_metrics;
158
225
total_metrics.Begin ();
159
226
160
227
std::vector<std::thread> threads;
228
+ using ModifyRecord = std::unordered_map<page_id_t , uint64_t >;
229
+
230
+ for (size_t thread_id = 0 ; thread_id < scan_thread_n; thread_id++) {
231
+ threads.emplace_back ([bustub_page_cnt, scan_thread_n, thread_id, &page_ids, &bpm, duration_ms, &total_metrics] {
232
+ ModifyRecord records;
161
233
162
- for (size_t thread_id = 0 ; thread_id < BUSTUB_SCAN_THREAD; thread_id++) {
163
- threads.emplace_back (std::thread ([thread_id, &page_ids, &bpm, duration_ms, &total_metrics] {
164
234
BpmMetrics metrics (fmt::format (" scan {:>2}" , thread_id), duration_ms);
165
235
metrics.Begin ();
166
236
167
- size_t page_idx = BUSTUB_PAGE_CNT * thread_id / BUSTUB_SCAN_THREAD;
237
+ size_t page_idx_start = bustub_page_cnt * thread_id / scan_thread_n;
238
+ size_t page_idx_end = bustub_page_cnt * (thread_id + 1 ) / scan_thread_n;
239
+ size_t page_idx = page_idx_start;
168
240
169
241
while (!metrics.ShouldFinish ()) {
170
242
auto *page = bpm->FetchPage (page_ids[page_idx], AccessType::Scan);
171
243
if (page == nullptr ) {
172
244
continue ;
173
245
}
174
246
175
- char &ch = page->GetData ()[page_idx % 1024 ];
176
247
page->WLatch ();
177
- ch += 1 ;
178
- if (ch == 0 ) {
179
- ch = 1 ;
180
- }
248
+ auto &seed = records[page_idx] ;
249
+ CheckPageConsistent (page-> GetData (), page_idx, seed);
250
+ seed = seed + 1 ;
251
+ ModifyPage (page-> GetData (), page_idx, seed);
181
252
page->WUnlatch ();
182
253
183
254
bpm->UnpinPage (page->GetPageId (), true , AccessType::Scan);
184
- page_idx = (page_idx + 1 ) % BUSTUB_PAGE_CNT;
255
+ page_idx += 1 ;
256
+ if (page_idx >= page_idx_end) {
257
+ page_idx = page_idx_start;
258
+ }
185
259
metrics.Tick ();
186
260
metrics.Report ();
187
261
}
188
262
189
263
total_metrics.ReportScan (metrics.cnt_ );
190
- })) ;
264
+ });
191
265
}
192
266
193
- for (size_t thread_id = 0 ; thread_id < BUSTUB_GET_THREAD ; thread_id++) {
194
- threads.emplace_back (std::thread ( [thread_id, &page_ids, &bpm, duration_ms, &total_metrics] {
267
+ for (size_t thread_id = 0 ; thread_id < get_thread_n ; thread_id++) {
268
+ threads.emplace_back ([thread_id, &page_ids, &bpm, bustub_page_cnt , duration_ms, &total_metrics] {
195
269
std::random_device r;
196
270
std::default_random_engine gen (r ());
197
- zipfian_int_distribution<size_t > dist (0 , BUSTUB_PAGE_CNT - 1 , 0.8 );
271
+ zipfian_int_distribution<size_t > dist (0 , bustub_page_cnt - 1 , 0.8 );
198
272
199
273
BpmMetrics metrics (fmt::format (" get {:>2}" , thread_id), duration_ms);
200
274
metrics.Begin ();
201
275
202
276
while (!metrics.ShouldFinish ()) {
203
277
auto page_idx = dist (gen);
204
- auto *page = bpm->FetchPage (page_ids[page_idx], AccessType::Get );
278
+ auto *page = bpm->FetchPage (page_ids[page_idx], AccessType::Lookup );
205
279
if (page == nullptr ) {
206
280
continue ;
207
281
}
208
282
209
283
page->RLatch ();
210
- char ch = page->GetData ()[page_idx % 1024 ] ;
284
+ CheckPageConsistentNoSeed ( page->GetData (), page_idx) ;
211
285
page->RUnlatch ();
212
- if (ch == 0 ) {
213
- throw std::runtime_error (" invalid data" );
214
- }
215
286
216
- bpm->UnpinPage (page->GetPageId (), false , AccessType::Get );
287
+ bpm->UnpinPage (page->GetPageId (), false , AccessType::Lookup );
217
288
metrics.Tick ();
218
289
metrics.Report ();
219
290
}
220
291
221
292
total_metrics.ReportGet (metrics.cnt_ );
222
- })) ;
293
+ });
223
294
}
224
295
225
296
for (auto &thread : threads) {
0 commit comments