]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | // |
6 | #include <algorithm> | |
7 | #include <iostream> | |
8 | #include <thread> | |
9 | #include <vector> | |
10 | ||
11 | #include "monitoring/histogram.h" | |
12 | #include "monitoring/instrumented_mutex.h" | |
494da23a | 13 | #include "monitoring/perf_context_imp.h" |
7c673cae FG |
14 | #include "monitoring/thread_status_util.h" |
15 | #include "port/port.h" | |
16 | #include "rocksdb/db.h" | |
17 | #include "rocksdb/memtablerep.h" | |
18 | #include "rocksdb/perf_context.h" | |
19 | #include "rocksdb/slice_transform.h" | |
f67539c2 | 20 | #include "test_util/testharness.h" |
7c673cae FG |
21 | #include "util/stop_watch.h" |
22 | #include "util/string_util.h" | |
7c673cae FG |
23 | #include "utilities/merge_operators.h" |
24 | ||
25 | bool FLAGS_random_key = false; | |
26 | bool FLAGS_use_set_based_memetable = false; | |
27 | int FLAGS_total_keys = 100; | |
28 | int FLAGS_write_buffer_size = 1000000000; | |
29 | int FLAGS_max_write_buffer_number = 8; | |
30 | int FLAGS_min_write_buffer_number_to_merge = 7; | |
31 | bool FLAGS_verbose = false; | |
32 | ||
33 | // Path to the database on file system | |
f67539c2 TL |
34 | const std::string kDbName = |
35 | ROCKSDB_NAMESPACE::test::PerThreadDBPath("perf_context_test"); | |
7c673cae | 36 | |
f67539c2 | 37 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
38 | |
39 | std::shared_ptr<DB> OpenDb(bool read_only = false) { | |
40 | DB* db; | |
41 | Options options; | |
42 | options.create_if_missing = true; | |
43 | options.max_open_files = -1; | |
44 | options.write_buffer_size = FLAGS_write_buffer_size; | |
45 | options.max_write_buffer_number = FLAGS_max_write_buffer_number; | |
46 | options.min_write_buffer_number_to_merge = | |
47 | FLAGS_min_write_buffer_number_to_merge; | |
48 | ||
49 | if (FLAGS_use_set_based_memetable) { | |
50 | #ifndef ROCKSDB_LITE | |
f67539c2 TL |
51 | options.prefix_extractor.reset( |
52 | ROCKSDB_NAMESPACE::NewFixedPrefixTransform(0)); | |
7c673cae FG |
53 | options.memtable_factory.reset(NewHashSkipListRepFactory()); |
54 | #endif // ROCKSDB_LITE | |
55 | } | |
56 | ||
57 | Status s; | |
58 | if (!read_only) { | |
59 | s = DB::Open(options, kDbName, &db); | |
60 | } else { | |
61 | s = DB::OpenForReadOnly(options, kDbName, &db); | |
62 | } | |
63 | EXPECT_OK(s); | |
64 | return std::shared_ptr<DB>(db); | |
65 | } | |
66 | ||
67 | class PerfContextTest : public testing::Test {}; | |
68 | ||
69 | TEST_F(PerfContextTest, SeekIntoDeletion) { | |
70 | DestroyDB(kDbName, Options()); | |
71 | auto db = OpenDb(); | |
72 | WriteOptions write_options; | |
73 | ReadOptions read_options; | |
74 | ||
75 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
76 | std::string key = "k" + ToString(i); | |
77 | std::string value = "v" + ToString(i); | |
78 | ||
79 | db->Put(write_options, key, value); | |
80 | } | |
81 | ||
82 | for (int i = 0; i < FLAGS_total_keys -1 ; ++i) { | |
83 | std::string key = "k" + ToString(i); | |
84 | db->Delete(write_options, key); | |
85 | } | |
86 | ||
87 | HistogramImpl hist_get; | |
88 | HistogramImpl hist_get_time; | |
89 | for (int i = 0; i < FLAGS_total_keys - 1; ++i) { | |
90 | std::string key = "k" + ToString(i); | |
91 | std::string value; | |
92 | ||
11fdf7f2 | 93 | get_perf_context()->Reset(); |
7c673cae FG |
94 | StopWatchNano timer(Env::Default()); |
95 | timer.Start(); | |
96 | auto status = db->Get(read_options, key, &value); | |
97 | auto elapsed_nanos = timer.ElapsedNanos(); | |
98 | ASSERT_TRUE(status.IsNotFound()); | |
11fdf7f2 | 99 | hist_get.Add(get_perf_context()->user_key_comparison_count); |
7c673cae FG |
100 | hist_get_time.Add(elapsed_nanos); |
101 | } | |
102 | ||
103 | if (FLAGS_verbose) { | |
104 | std::cout << "Get user key comparison: \n" << hist_get.ToString() | |
105 | << "Get time: \n" << hist_get_time.ToString(); | |
106 | } | |
107 | ||
108 | { | |
109 | HistogramImpl hist_seek_to_first; | |
110 | std::unique_ptr<Iterator> iter(db->NewIterator(read_options)); | |
111 | ||
11fdf7f2 | 112 | get_perf_context()->Reset(); |
7c673cae FG |
113 | StopWatchNano timer(Env::Default(), true); |
114 | iter->SeekToFirst(); | |
11fdf7f2 | 115 | hist_seek_to_first.Add(get_perf_context()->user_key_comparison_count); |
7c673cae FG |
116 | auto elapsed_nanos = timer.ElapsedNanos(); |
117 | ||
118 | if (FLAGS_verbose) { | |
119 | std::cout << "SeekToFirst uesr key comparison: \n" | |
120 | << hist_seek_to_first.ToString() | |
11fdf7f2 | 121 | << "ikey skipped: " << get_perf_context()->internal_key_skipped_count |
7c673cae FG |
122 | << "\n" |
123 | << "idelete skipped: " | |
11fdf7f2 | 124 | << get_perf_context()->internal_delete_skipped_count << "\n" |
7c673cae FG |
125 | << "elapsed: " << elapsed_nanos << "\n"; |
126 | } | |
127 | } | |
128 | ||
129 | HistogramImpl hist_seek; | |
130 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
131 | std::unique_ptr<Iterator> iter(db->NewIterator(read_options)); | |
132 | std::string key = "k" + ToString(i); | |
133 | ||
11fdf7f2 | 134 | get_perf_context()->Reset(); |
7c673cae FG |
135 | StopWatchNano timer(Env::Default(), true); |
136 | iter->Seek(key); | |
137 | auto elapsed_nanos = timer.ElapsedNanos(); | |
11fdf7f2 | 138 | hist_seek.Add(get_perf_context()->user_key_comparison_count); |
7c673cae | 139 | if (FLAGS_verbose) { |
11fdf7f2 TL |
140 | std::cout << "seek cmp: " << get_perf_context()->user_key_comparison_count |
141 | << " ikey skipped " << get_perf_context()->internal_key_skipped_count | |
7c673cae | 142 | << " idelete skipped " |
11fdf7f2 | 143 | << get_perf_context()->internal_delete_skipped_count |
7c673cae FG |
144 | << " elapsed: " << elapsed_nanos << "ns\n"; |
145 | } | |
146 | ||
11fdf7f2 | 147 | get_perf_context()->Reset(); |
7c673cae FG |
148 | ASSERT_TRUE(iter->Valid()); |
149 | StopWatchNano timer2(Env::Default(), true); | |
150 | iter->Next(); | |
151 | auto elapsed_nanos2 = timer2.ElapsedNanos(); | |
152 | if (FLAGS_verbose) { | |
11fdf7f2 | 153 | std::cout << "next cmp: " << get_perf_context()->user_key_comparison_count |
7c673cae FG |
154 | << "elapsed: " << elapsed_nanos2 << "ns\n"; |
155 | } | |
156 | } | |
157 | ||
158 | if (FLAGS_verbose) { | |
159 | std::cout << "Seek uesr key comparison: \n" << hist_seek.ToString(); | |
160 | } | |
161 | } | |
162 | ||
163 | TEST_F(PerfContextTest, StopWatchNanoOverhead) { | |
164 | // profile the timer cost by itself! | |
165 | const int kTotalIterations = 1000000; | |
166 | std::vector<uint64_t> timings(kTotalIterations); | |
167 | ||
168 | StopWatchNano timer(Env::Default(), true); | |
169 | for (auto& timing : timings) { | |
170 | timing = timer.ElapsedNanos(true /* reset */); | |
171 | } | |
172 | ||
173 | HistogramImpl histogram; | |
174 | for (const auto timing : timings) { | |
175 | histogram.Add(timing); | |
176 | } | |
177 | ||
178 | if (FLAGS_verbose) { | |
179 | std::cout << histogram.ToString(); | |
180 | } | |
181 | } | |
182 | ||
183 | TEST_F(PerfContextTest, StopWatchOverhead) { | |
184 | // profile the timer cost by itself! | |
185 | const int kTotalIterations = 1000000; | |
186 | uint64_t elapsed = 0; | |
187 | std::vector<uint64_t> timings(kTotalIterations); | |
188 | ||
189 | StopWatch timer(Env::Default(), nullptr, 0, &elapsed); | |
190 | for (auto& timing : timings) { | |
191 | timing = elapsed; | |
192 | } | |
193 | ||
194 | HistogramImpl histogram; | |
195 | uint64_t prev_timing = 0; | |
196 | for (const auto timing : timings) { | |
197 | histogram.Add(timing - prev_timing); | |
198 | prev_timing = timing; | |
199 | } | |
200 | ||
201 | if (FLAGS_verbose) { | |
202 | std::cout << histogram.ToString(); | |
203 | } | |
204 | } | |
205 | ||
206 | void ProfileQueries(bool enabled_time = false) { | |
207 | DestroyDB(kDbName, Options()); // Start this test with a fresh DB | |
208 | ||
209 | auto db = OpenDb(); | |
210 | ||
211 | WriteOptions write_options; | |
212 | ReadOptions read_options; | |
213 | ||
214 | HistogramImpl hist_put; | |
215 | ||
216 | HistogramImpl hist_get; | |
217 | HistogramImpl hist_get_snapshot; | |
218 | HistogramImpl hist_get_memtable; | |
219 | HistogramImpl hist_get_files; | |
220 | HistogramImpl hist_get_post_process; | |
221 | HistogramImpl hist_num_memtable_checked; | |
222 | ||
223 | HistogramImpl hist_mget; | |
224 | HistogramImpl hist_mget_snapshot; | |
225 | HistogramImpl hist_mget_memtable; | |
226 | HistogramImpl hist_mget_files; | |
227 | HistogramImpl hist_mget_post_process; | |
228 | HistogramImpl hist_mget_num_memtable_checked; | |
229 | ||
230 | HistogramImpl hist_write_pre_post; | |
231 | HistogramImpl hist_write_wal_time; | |
232 | HistogramImpl hist_write_memtable_time; | |
11fdf7f2 TL |
233 | HistogramImpl hist_write_delay_time; |
234 | HistogramImpl hist_write_thread_wait_nanos; | |
235 | HistogramImpl hist_write_scheduling_time; | |
7c673cae FG |
236 | |
237 | uint64_t total_db_mutex_nanos = 0; | |
238 | ||
239 | if (FLAGS_verbose) { | |
240 | std::cout << "Inserting " << FLAGS_total_keys << " key/value pairs\n...\n"; | |
241 | } | |
242 | ||
243 | std::vector<int> keys; | |
244 | const int kFlushFlag = -1; | |
245 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
246 | keys.push_back(i); | |
247 | if (i == FLAGS_total_keys / 2) { | |
248 | // Issuing a flush in the middle. | |
249 | keys.push_back(kFlushFlag); | |
250 | } | |
251 | } | |
252 | ||
253 | if (FLAGS_random_key) { | |
254 | std::random_shuffle(keys.begin(), keys.end()); | |
255 | } | |
256 | #ifndef NDEBUG | |
257 | ThreadStatusUtil::TEST_SetStateDelay(ThreadStatus::STATE_MUTEX_WAIT, 1U); | |
258 | #endif | |
259 | int num_mutex_waited = 0; | |
260 | for (const int i : keys) { | |
261 | if (i == kFlushFlag) { | |
262 | FlushOptions fo; | |
263 | db->Flush(fo); | |
264 | continue; | |
265 | } | |
266 | ||
267 | std::string key = "k" + ToString(i); | |
268 | std::string value = "v" + ToString(i); | |
269 | ||
270 | std::vector<std::string> values; | |
271 | ||
11fdf7f2 | 272 | get_perf_context()->Reset(); |
7c673cae FG |
273 | db->Put(write_options, key, value); |
274 | if (++num_mutex_waited > 3) { | |
275 | #ifndef NDEBUG | |
276 | ThreadStatusUtil::TEST_SetStateDelay(ThreadStatus::STATE_MUTEX_WAIT, 0U); | |
277 | #endif | |
278 | } | |
11fdf7f2 TL |
279 | hist_write_pre_post.Add( |
280 | get_perf_context()->write_pre_and_post_process_time); | |
281 | hist_write_wal_time.Add(get_perf_context()->write_wal_time); | |
282 | hist_write_memtable_time.Add(get_perf_context()->write_memtable_time); | |
283 | hist_write_delay_time.Add(get_perf_context()->write_delay_time); | |
284 | hist_write_thread_wait_nanos.Add( | |
285 | get_perf_context()->write_thread_wait_nanos); | |
286 | hist_write_scheduling_time.Add( | |
287 | get_perf_context()->write_scheduling_flushes_compactions_time); | |
288 | hist_put.Add(get_perf_context()->user_key_comparison_count); | |
289 | total_db_mutex_nanos += get_perf_context()->db_mutex_lock_nanos; | |
7c673cae FG |
290 | } |
291 | #ifndef NDEBUG | |
292 | ThreadStatusUtil::TEST_SetStateDelay(ThreadStatus::STATE_MUTEX_WAIT, 0U); | |
293 | #endif | |
294 | ||
295 | for (const int i : keys) { | |
296 | if (i == kFlushFlag) { | |
297 | continue; | |
298 | } | |
299 | std::string key = "k" + ToString(i); | |
300 | std::string expected_value = "v" + ToString(i); | |
301 | std::string value; | |
302 | ||
303 | std::vector<Slice> multiget_keys = {Slice(key)}; | |
304 | std::vector<std::string> values; | |
305 | ||
11fdf7f2 | 306 | get_perf_context()->Reset(); |
7c673cae FG |
307 | ASSERT_OK(db->Get(read_options, key, &value)); |
308 | ASSERT_EQ(expected_value, value); | |
11fdf7f2 TL |
309 | hist_get_snapshot.Add(get_perf_context()->get_snapshot_time); |
310 | hist_get_memtable.Add(get_perf_context()->get_from_memtable_time); | |
311 | hist_get_files.Add(get_perf_context()->get_from_output_files_time); | |
312 | hist_num_memtable_checked.Add(get_perf_context()->get_from_memtable_count); | |
313 | hist_get_post_process.Add(get_perf_context()->get_post_process_time); | |
314 | hist_get.Add(get_perf_context()->user_key_comparison_count); | |
315 | ||
316 | get_perf_context()->Reset(); | |
7c673cae | 317 | db->MultiGet(read_options, multiget_keys, &values); |
11fdf7f2 TL |
318 | hist_mget_snapshot.Add(get_perf_context()->get_snapshot_time); |
319 | hist_mget_memtable.Add(get_perf_context()->get_from_memtable_time); | |
320 | hist_mget_files.Add(get_perf_context()->get_from_output_files_time); | |
321 | hist_mget_num_memtable_checked.Add(get_perf_context()->get_from_memtable_count); | |
322 | hist_mget_post_process.Add(get_perf_context()->get_post_process_time); | |
323 | hist_mget.Add(get_perf_context()->user_key_comparison_count); | |
7c673cae FG |
324 | } |
325 | ||
326 | if (FLAGS_verbose) { | |
327 | std::cout << "Put uesr key comparison: \n" << hist_put.ToString() | |
328 | << "Get uesr key comparison: \n" << hist_get.ToString() | |
329 | << "MultiGet uesr key comparison: \n" << hist_get.ToString(); | |
330 | std::cout << "Put(): Pre and Post Process Time: \n" | |
331 | << hist_write_pre_post.ToString() << " Writing WAL time: \n" | |
332 | << hist_write_wal_time.ToString() << "\n" | |
333 | << " Writing Mem Table time: \n" | |
334 | << hist_write_memtable_time.ToString() << "\n" | |
11fdf7f2 TL |
335 | << " Write Delay: \n" << hist_write_delay_time.ToString() << "\n" |
336 | << " Waiting for Batch time: \n" | |
337 | << hist_write_thread_wait_nanos.ToString() << "\n" | |
338 | << " Scheduling Flushes and Compactions Time: \n" | |
339 | << hist_write_scheduling_time.ToString() << "\n" | |
7c673cae FG |
340 | << " Total DB mutex nanos: \n" << total_db_mutex_nanos << "\n"; |
341 | ||
342 | std::cout << "Get(): Time to get snapshot: \n" | |
343 | << hist_get_snapshot.ToString() | |
344 | << " Time to get value from memtables: \n" | |
345 | << hist_get_memtable.ToString() << "\n" | |
346 | << " Time to get value from output files: \n" | |
347 | << hist_get_files.ToString() << "\n" | |
348 | << " Number of memtables checked: \n" | |
349 | << hist_num_memtable_checked.ToString() << "\n" | |
350 | << " Time to post process: \n" << hist_get_post_process.ToString() | |
351 | << "\n"; | |
352 | ||
353 | std::cout << "MultiGet(): Time to get snapshot: \n" | |
354 | << hist_mget_snapshot.ToString() | |
355 | << " Time to get value from memtables: \n" | |
356 | << hist_mget_memtable.ToString() << "\n" | |
357 | << " Time to get value from output files: \n" | |
358 | << hist_mget_files.ToString() << "\n" | |
359 | << " Number of memtables checked: \n" | |
360 | << hist_mget_num_memtable_checked.ToString() << "\n" | |
361 | << " Time to post process: \n" | |
362 | << hist_mget_post_process.ToString() << "\n"; | |
363 | } | |
364 | ||
365 | if (enabled_time) { | |
366 | ASSERT_GT(hist_get.Average(), 0); | |
367 | ASSERT_GT(hist_get_snapshot.Average(), 0); | |
368 | ASSERT_GT(hist_get_memtable.Average(), 0); | |
369 | ASSERT_GT(hist_get_files.Average(), 0); | |
370 | ASSERT_GT(hist_get_post_process.Average(), 0); | |
371 | ASSERT_GT(hist_num_memtable_checked.Average(), 0); | |
372 | ||
373 | ASSERT_GT(hist_mget.Average(), 0); | |
374 | ASSERT_GT(hist_mget_snapshot.Average(), 0); | |
375 | ASSERT_GT(hist_mget_memtable.Average(), 0); | |
376 | ASSERT_GT(hist_mget_files.Average(), 0); | |
377 | ASSERT_GT(hist_mget_post_process.Average(), 0); | |
378 | ASSERT_GT(hist_mget_num_memtable_checked.Average(), 0); | |
11fdf7f2 TL |
379 | |
380 | EXPECT_GT(hist_write_pre_post.Average(), 0); | |
381 | EXPECT_GT(hist_write_wal_time.Average(), 0); | |
382 | EXPECT_GT(hist_write_memtable_time.Average(), 0); | |
383 | EXPECT_EQ(hist_write_delay_time.Average(), 0); | |
384 | EXPECT_EQ(hist_write_thread_wait_nanos.Average(), 0); | |
385 | EXPECT_GT(hist_write_scheduling_time.Average(), 0); | |
386 | ||
7c673cae FG |
387 | #ifndef NDEBUG |
388 | ASSERT_GT(total_db_mutex_nanos, 2000U); | |
389 | #endif | |
390 | } | |
391 | ||
392 | db.reset(); | |
393 | db = OpenDb(true); | |
394 | ||
395 | hist_get.Clear(); | |
396 | hist_get_snapshot.Clear(); | |
397 | hist_get_memtable.Clear(); | |
398 | hist_get_files.Clear(); | |
399 | hist_get_post_process.Clear(); | |
400 | hist_num_memtable_checked.Clear(); | |
401 | ||
402 | hist_mget.Clear(); | |
403 | hist_mget_snapshot.Clear(); | |
404 | hist_mget_memtable.Clear(); | |
405 | hist_mget_files.Clear(); | |
406 | hist_mget_post_process.Clear(); | |
407 | hist_mget_num_memtable_checked.Clear(); | |
408 | ||
409 | for (const int i : keys) { | |
410 | if (i == kFlushFlag) { | |
411 | continue; | |
412 | } | |
413 | std::string key = "k" + ToString(i); | |
414 | std::string expected_value = "v" + ToString(i); | |
415 | std::string value; | |
416 | ||
417 | std::vector<Slice> multiget_keys = {Slice(key)}; | |
418 | std::vector<std::string> values; | |
419 | ||
11fdf7f2 | 420 | get_perf_context()->Reset(); |
7c673cae FG |
421 | ASSERT_OK(db->Get(read_options, key, &value)); |
422 | ASSERT_EQ(expected_value, value); | |
11fdf7f2 TL |
423 | hist_get_snapshot.Add(get_perf_context()->get_snapshot_time); |
424 | hist_get_memtable.Add(get_perf_context()->get_from_memtable_time); | |
425 | hist_get_files.Add(get_perf_context()->get_from_output_files_time); | |
426 | hist_num_memtable_checked.Add(get_perf_context()->get_from_memtable_count); | |
427 | hist_get_post_process.Add(get_perf_context()->get_post_process_time); | |
428 | hist_get.Add(get_perf_context()->user_key_comparison_count); | |
429 | ||
430 | get_perf_context()->Reset(); | |
7c673cae | 431 | db->MultiGet(read_options, multiget_keys, &values); |
11fdf7f2 TL |
432 | hist_mget_snapshot.Add(get_perf_context()->get_snapshot_time); |
433 | hist_mget_memtable.Add(get_perf_context()->get_from_memtable_time); | |
434 | hist_mget_files.Add(get_perf_context()->get_from_output_files_time); | |
435 | hist_mget_num_memtable_checked.Add(get_perf_context()->get_from_memtable_count); | |
436 | hist_mget_post_process.Add(get_perf_context()->get_post_process_time); | |
437 | hist_mget.Add(get_perf_context()->user_key_comparison_count); | |
7c673cae FG |
438 | } |
439 | ||
440 | if (FLAGS_verbose) { | |
441 | std::cout << "ReadOnly Get uesr key comparison: \n" << hist_get.ToString() | |
442 | << "ReadOnly MultiGet uesr key comparison: \n" | |
443 | << hist_mget.ToString(); | |
444 | ||
445 | std::cout << "ReadOnly Get(): Time to get snapshot: \n" | |
446 | << hist_get_snapshot.ToString() | |
447 | << " Time to get value from memtables: \n" | |
448 | << hist_get_memtable.ToString() << "\n" | |
449 | << " Time to get value from output files: \n" | |
450 | << hist_get_files.ToString() << "\n" | |
451 | << " Number of memtables checked: \n" | |
452 | << hist_num_memtable_checked.ToString() << "\n" | |
453 | << " Time to post process: \n" << hist_get_post_process.ToString() | |
454 | << "\n"; | |
455 | ||
456 | std::cout << "ReadOnly MultiGet(): Time to get snapshot: \n" | |
457 | << hist_mget_snapshot.ToString() | |
458 | << " Time to get value from memtables: \n" | |
459 | << hist_mget_memtable.ToString() << "\n" | |
460 | << " Time to get value from output files: \n" | |
461 | << hist_mget_files.ToString() << "\n" | |
462 | << " Number of memtables checked: \n" | |
463 | << hist_mget_num_memtable_checked.ToString() << "\n" | |
464 | << " Time to post process: \n" | |
465 | << hist_mget_post_process.ToString() << "\n"; | |
466 | } | |
467 | ||
468 | if (enabled_time) { | |
469 | ASSERT_GT(hist_get.Average(), 0); | |
470 | ASSERT_GT(hist_get_memtable.Average(), 0); | |
471 | ASSERT_GT(hist_get_files.Average(), 0); | |
472 | ASSERT_GT(hist_num_memtable_checked.Average(), 0); | |
473 | // In read-only mode Get(), no super version operation is needed | |
474 | ASSERT_EQ(hist_get_post_process.Average(), 0); | |
11fdf7f2 | 475 | ASSERT_GT(hist_get_snapshot.Average(), 0); |
7c673cae FG |
476 | |
477 | ASSERT_GT(hist_mget.Average(), 0); | |
478 | ASSERT_GT(hist_mget_snapshot.Average(), 0); | |
479 | ASSERT_GT(hist_mget_memtable.Average(), 0); | |
480 | ASSERT_GT(hist_mget_files.Average(), 0); | |
481 | ASSERT_GT(hist_mget_post_process.Average(), 0); | |
482 | ASSERT_GT(hist_mget_num_memtable_checked.Average(), 0); | |
483 | } | |
484 | } | |
485 | ||
486 | #ifndef ROCKSDB_LITE | |
487 | TEST_F(PerfContextTest, KeyComparisonCount) { | |
488 | SetPerfLevel(kEnableCount); | |
489 | ProfileQueries(); | |
490 | ||
491 | SetPerfLevel(kDisable); | |
492 | ProfileQueries(); | |
493 | ||
494 | SetPerfLevel(kEnableTime); | |
495 | ProfileQueries(true); | |
496 | } | |
497 | #endif // ROCKSDB_LITE | |
498 | ||
499 | // make perf_context_test | |
500 | // export ROCKSDB_TESTS=PerfContextTest.SeekKeyComparison | |
501 | // For one memtable: | |
502 | // ./perf_context_test --write_buffer_size=500000 --total_keys=10000 | |
503 | // For two memtables: | |
504 | // ./perf_context_test --write_buffer_size=250000 --total_keys=10000 | |
505 | // Specify --random_key=1 to shuffle the key before insertion | |
506 | // Results show that, for sequential insertion, worst-case Seek Key comparison | |
507 | // is close to the total number of keys (linear), when there is only one | |
508 | // memtable. When there are two memtables, even the avg Seek Key comparison | |
509 | // starts to become linear to the input size. | |
510 | ||
511 | TEST_F(PerfContextTest, SeekKeyComparison) { | |
512 | DestroyDB(kDbName, Options()); | |
513 | auto db = OpenDb(); | |
514 | WriteOptions write_options; | |
515 | ReadOptions read_options; | |
516 | ||
517 | if (FLAGS_verbose) { | |
518 | std::cout << "Inserting " << FLAGS_total_keys << " key/value pairs\n...\n"; | |
519 | } | |
520 | ||
521 | std::vector<int> keys; | |
522 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
523 | keys.push_back(i); | |
524 | } | |
525 | ||
526 | if (FLAGS_random_key) { | |
527 | std::random_shuffle(keys.begin(), keys.end()); | |
528 | } | |
529 | ||
530 | HistogramImpl hist_put_time; | |
531 | HistogramImpl hist_wal_time; | |
532 | HistogramImpl hist_time_diff; | |
533 | ||
534 | SetPerfLevel(kEnableTime); | |
535 | StopWatchNano timer(Env::Default()); | |
536 | for (const int i : keys) { | |
537 | std::string key = "k" + ToString(i); | |
538 | std::string value = "v" + ToString(i); | |
539 | ||
11fdf7f2 | 540 | get_perf_context()->Reset(); |
7c673cae FG |
541 | timer.Start(); |
542 | db->Put(write_options, key, value); | |
543 | auto put_time = timer.ElapsedNanos(); | |
544 | hist_put_time.Add(put_time); | |
11fdf7f2 TL |
545 | hist_wal_time.Add(get_perf_context()->write_wal_time); |
546 | hist_time_diff.Add(put_time - get_perf_context()->write_wal_time); | |
7c673cae FG |
547 | } |
548 | ||
549 | if (FLAGS_verbose) { | |
550 | std::cout << "Put time:\n" << hist_put_time.ToString() << "WAL time:\n" | |
551 | << hist_wal_time.ToString() << "time diff:\n" | |
552 | << hist_time_diff.ToString(); | |
553 | } | |
554 | ||
555 | HistogramImpl hist_seek; | |
556 | HistogramImpl hist_next; | |
557 | ||
558 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
559 | std::string key = "k" + ToString(i); | |
560 | std::string value = "v" + ToString(i); | |
561 | ||
562 | std::unique_ptr<Iterator> iter(db->NewIterator(read_options)); | |
11fdf7f2 | 563 | get_perf_context()->Reset(); |
7c673cae FG |
564 | iter->Seek(key); |
565 | ASSERT_TRUE(iter->Valid()); | |
566 | ASSERT_EQ(iter->value().ToString(), value); | |
11fdf7f2 | 567 | hist_seek.Add(get_perf_context()->user_key_comparison_count); |
7c673cae FG |
568 | } |
569 | ||
570 | std::unique_ptr<Iterator> iter(db->NewIterator(read_options)); | |
571 | for (iter->SeekToFirst(); iter->Valid();) { | |
11fdf7f2 | 572 | get_perf_context()->Reset(); |
7c673cae | 573 | iter->Next(); |
11fdf7f2 | 574 | hist_next.Add(get_perf_context()->user_key_comparison_count); |
7c673cae FG |
575 | } |
576 | ||
577 | if (FLAGS_verbose) { | |
578 | std::cout << "Seek:\n" << hist_seek.ToString() << "Next:\n" | |
579 | << hist_next.ToString(); | |
580 | } | |
581 | } | |
582 | ||
583 | TEST_F(PerfContextTest, DBMutexLockCounter) { | |
584 | int stats_code[] = {0, static_cast<int>(DB_MUTEX_WAIT_MICROS)}; | |
494da23a | 585 | for (PerfLevel perf_level_test : |
7c673cae FG |
586 | {PerfLevel::kEnableTimeExceptForMutex, PerfLevel::kEnableTime}) { |
587 | for (int c = 0; c < 2; ++c) { | |
588 | InstrumentedMutex mutex(nullptr, Env::Default(), stats_code[c]); | |
589 | mutex.Lock(); | |
f67539c2 | 590 | ROCKSDB_NAMESPACE::port::Thread child_thread([&] { |
494da23a | 591 | SetPerfLevel(perf_level_test); |
11fdf7f2 TL |
592 | get_perf_context()->Reset(); |
593 | ASSERT_EQ(get_perf_context()->db_mutex_lock_nanos, 0); | |
7c673cae FG |
594 | mutex.Lock(); |
595 | mutex.Unlock(); | |
494da23a | 596 | if (perf_level_test == PerfLevel::kEnableTimeExceptForMutex || |
7c673cae | 597 | stats_code[c] != DB_MUTEX_WAIT_MICROS) { |
11fdf7f2 | 598 | ASSERT_EQ(get_perf_context()->db_mutex_lock_nanos, 0); |
7c673cae FG |
599 | } else { |
600 | // increment the counter only when it's a DB Mutex | |
11fdf7f2 | 601 | ASSERT_GT(get_perf_context()->db_mutex_lock_nanos, 0); |
7c673cae FG |
602 | } |
603 | }); | |
604 | Env::Default()->SleepForMicroseconds(100); | |
605 | mutex.Unlock(); | |
606 | child_thread.join(); | |
607 | } | |
608 | } | |
609 | } | |
610 | ||
611 | TEST_F(PerfContextTest, FalseDBMutexWait) { | |
612 | SetPerfLevel(kEnableTime); | |
613 | int stats_code[] = {0, static_cast<int>(DB_MUTEX_WAIT_MICROS)}; | |
614 | for (int c = 0; c < 2; ++c) { | |
615 | InstrumentedMutex mutex(nullptr, Env::Default(), stats_code[c]); | |
616 | InstrumentedCondVar lock(&mutex); | |
11fdf7f2 | 617 | get_perf_context()->Reset(); |
7c673cae FG |
618 | mutex.Lock(); |
619 | lock.TimedWait(100); | |
620 | mutex.Unlock(); | |
621 | if (stats_code[c] == static_cast<int>(DB_MUTEX_WAIT_MICROS)) { | |
622 | // increment the counter only when it's a DB Mutex | |
11fdf7f2 | 623 | ASSERT_GT(get_perf_context()->db_condition_wait_nanos, 0); |
7c673cae | 624 | } else { |
11fdf7f2 | 625 | ASSERT_EQ(get_perf_context()->db_condition_wait_nanos, 0); |
7c673cae FG |
626 | } |
627 | } | |
628 | } | |
629 | ||
630 | TEST_F(PerfContextTest, ToString) { | |
11fdf7f2 TL |
631 | get_perf_context()->Reset(); |
632 | get_perf_context()->block_read_count = 12345; | |
7c673cae | 633 | |
11fdf7f2 | 634 | std::string zero_included = get_perf_context()->ToString(); |
7c673cae FG |
635 | ASSERT_NE(std::string::npos, zero_included.find("= 0")); |
636 | ASSERT_NE(std::string::npos, zero_included.find("= 12345")); | |
637 | ||
11fdf7f2 | 638 | std::string zero_excluded = get_perf_context()->ToString(true); |
7c673cae FG |
639 | ASSERT_EQ(std::string::npos, zero_excluded.find("= 0")); |
640 | ASSERT_NE(std::string::npos, zero_excluded.find("= 12345")); | |
641 | } | |
642 | ||
643 | TEST_F(PerfContextTest, MergeOperatorTime) { | |
644 | DestroyDB(kDbName, Options()); | |
645 | DB* db; | |
646 | Options options; | |
647 | options.create_if_missing = true; | |
648 | options.merge_operator = MergeOperators::CreateStringAppendOperator(); | |
649 | Status s = DB::Open(options, kDbName, &db); | |
650 | EXPECT_OK(s); | |
651 | ||
652 | std::string val; | |
653 | ASSERT_OK(db->Merge(WriteOptions(), "k1", "val1")); | |
654 | ASSERT_OK(db->Merge(WriteOptions(), "k1", "val2")); | |
655 | ASSERT_OK(db->Merge(WriteOptions(), "k1", "val3")); | |
656 | ASSERT_OK(db->Merge(WriteOptions(), "k1", "val4")); | |
657 | ||
658 | SetPerfLevel(kEnableTime); | |
11fdf7f2 | 659 | get_perf_context()->Reset(); |
7c673cae FG |
660 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); |
661 | #ifdef OS_SOLARIS | |
662 | for (int i = 0; i < 100; i++) { | |
663 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); | |
664 | } | |
665 | #endif | |
11fdf7f2 | 666 | EXPECT_GT(get_perf_context()->merge_operator_time_nanos, 0); |
7c673cae FG |
667 | |
668 | ASSERT_OK(db->Flush(FlushOptions())); | |
669 | ||
11fdf7f2 | 670 | get_perf_context()->Reset(); |
7c673cae FG |
671 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); |
672 | #ifdef OS_SOLARIS | |
673 | for (int i = 0; i < 100; i++) { | |
674 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); | |
675 | } | |
676 | #endif | |
11fdf7f2 | 677 | EXPECT_GT(get_perf_context()->merge_operator_time_nanos, 0); |
7c673cae FG |
678 | |
679 | ASSERT_OK(db->CompactRange(CompactRangeOptions(), nullptr, nullptr)); | |
680 | ||
11fdf7f2 | 681 | get_perf_context()->Reset(); |
7c673cae FG |
682 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); |
683 | #ifdef OS_SOLARIS | |
684 | for (int i = 0; i < 100; i++) { | |
685 | ASSERT_OK(db->Get(ReadOptions(), "k1", &val)); | |
686 | } | |
687 | #endif | |
11fdf7f2 | 688 | EXPECT_GT(get_perf_context()->merge_operator_time_nanos, 0); |
7c673cae FG |
689 | |
690 | delete db; | |
691 | } | |
494da23a TL |
692 | |
693 | TEST_F(PerfContextTest, CopyAndMove) { | |
694 | // Assignment operator | |
695 | { | |
696 | get_perf_context()->Reset(); | |
697 | get_perf_context()->EnablePerLevelPerfContext(); | |
698 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5); | |
699 | ASSERT_EQ( | |
700 | 1, | |
701 | (*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful); | |
702 | PerfContext perf_context_assign; | |
703 | perf_context_assign = *get_perf_context(); | |
704 | ASSERT_EQ( | |
705 | 1, | |
706 | (*(perf_context_assign.level_to_perf_context))[5].bloom_filter_useful); | |
707 | get_perf_context()->ClearPerLevelPerfContext(); | |
708 | get_perf_context()->Reset(); | |
709 | ASSERT_EQ( | |
710 | 1, | |
711 | (*(perf_context_assign.level_to_perf_context))[5].bloom_filter_useful); | |
712 | perf_context_assign.ClearPerLevelPerfContext(); | |
713 | perf_context_assign.Reset(); | |
714 | } | |
715 | // Copy constructor | |
716 | { | |
717 | get_perf_context()->Reset(); | |
718 | get_perf_context()->EnablePerLevelPerfContext(); | |
719 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5); | |
720 | ASSERT_EQ( | |
721 | 1, | |
722 | (*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful); | |
723 | PerfContext perf_context_copy(*get_perf_context()); | |
724 | ASSERT_EQ( | |
725 | 1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful); | |
726 | get_perf_context()->ClearPerLevelPerfContext(); | |
727 | get_perf_context()->Reset(); | |
728 | ASSERT_EQ( | |
729 | 1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful); | |
730 | perf_context_copy.ClearPerLevelPerfContext(); | |
731 | perf_context_copy.Reset(); | |
732 | } | |
733 | // Move constructor | |
734 | { | |
735 | get_perf_context()->Reset(); | |
736 | get_perf_context()->EnablePerLevelPerfContext(); | |
737 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5); | |
738 | ASSERT_EQ( | |
739 | 1, | |
740 | (*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful); | |
741 | PerfContext perf_context_move = std::move(*get_perf_context()); | |
742 | ASSERT_EQ( | |
743 | 1, (*(perf_context_move.level_to_perf_context))[5].bloom_filter_useful); | |
744 | get_perf_context()->ClearPerLevelPerfContext(); | |
745 | get_perf_context()->Reset(); | |
746 | ASSERT_EQ( | |
747 | 1, (*(perf_context_move.level_to_perf_context))[5].bloom_filter_useful); | |
748 | perf_context_move.ClearPerLevelPerfContext(); | |
749 | perf_context_move.Reset(); | |
750 | } | |
751 | } | |
752 | ||
753 | TEST_F(PerfContextTest, PerfContextDisableEnable) { | |
754 | get_perf_context()->Reset(); | |
755 | get_perf_context()->EnablePerLevelPerfContext(); | |
756 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_positive, 1, 0); | |
757 | get_perf_context()->DisablePerLevelPerfContext(); | |
758 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5); | |
759 | get_perf_context()->EnablePerLevelPerfContext(); | |
760 | PERF_COUNTER_BY_LEVEL_ADD(block_cache_hit_count, 1, 0); | |
761 | get_perf_context()->DisablePerLevelPerfContext(); | |
762 | PerfContext perf_context_copy(*get_perf_context()); | |
763 | ASSERT_EQ(1, (*(perf_context_copy.level_to_perf_context))[0] | |
764 | .bloom_filter_full_positive); | |
765 | // this was set when per level perf context is disabled, should not be copied | |
766 | ASSERT_NE( | |
767 | 1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful); | |
768 | ASSERT_EQ( | |
769 | 1, (*(perf_context_copy.level_to_perf_context))[0].block_cache_hit_count); | |
770 | perf_context_copy.ClearPerLevelPerfContext(); | |
771 | perf_context_copy.Reset(); | |
772 | get_perf_context()->ClearPerLevelPerfContext(); | |
773 | get_perf_context()->Reset(); | |
774 | } | |
775 | ||
776 | TEST_F(PerfContextTest, PerfContextByLevelGetSet) { | |
777 | get_perf_context()->Reset(); | |
778 | get_perf_context()->EnablePerLevelPerfContext(); | |
779 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_positive, 1, 0); | |
780 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5); | |
781 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 7); | |
782 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 7); | |
783 | PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_true_positive, 1, 2); | |
784 | PERF_COUNTER_BY_LEVEL_ADD(block_cache_hit_count, 1, 0); | |
785 | PERF_COUNTER_BY_LEVEL_ADD(block_cache_hit_count, 5, 2); | |
786 | PERF_COUNTER_BY_LEVEL_ADD(block_cache_miss_count, 2, 3); | |
787 | PERF_COUNTER_BY_LEVEL_ADD(block_cache_miss_count, 4, 1); | |
788 | ASSERT_EQ( | |
789 | 0, (*(get_perf_context()->level_to_perf_context))[0].bloom_filter_useful); | |
790 | ASSERT_EQ( | |
791 | 1, (*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful); | |
792 | ASSERT_EQ( | |
793 | 2, (*(get_perf_context()->level_to_perf_context))[7].bloom_filter_useful); | |
794 | ASSERT_EQ(1, (*(get_perf_context()->level_to_perf_context))[0] | |
795 | .bloom_filter_full_positive); | |
796 | ASSERT_EQ(1, (*(get_perf_context()->level_to_perf_context))[2] | |
797 | .bloom_filter_full_true_positive); | |
798 | ASSERT_EQ(1, (*(get_perf_context()->level_to_perf_context))[0] | |
799 | .block_cache_hit_count); | |
800 | ASSERT_EQ(5, (*(get_perf_context()->level_to_perf_context))[2] | |
801 | .block_cache_hit_count); | |
802 | ASSERT_EQ(2, (*(get_perf_context()->level_to_perf_context))[3] | |
803 | .block_cache_miss_count); | |
804 | ASSERT_EQ(4, (*(get_perf_context()->level_to_perf_context))[1] | |
805 | .block_cache_miss_count); | |
806 | std::string zero_excluded = get_perf_context()->ToString(true); | |
807 | ASSERT_NE(std::string::npos, | |
808 | zero_excluded.find("bloom_filter_useful = 1@level5, 2@level7")); | |
809 | ASSERT_NE(std::string::npos, | |
810 | zero_excluded.find("bloom_filter_full_positive = 1@level0")); | |
811 | ASSERT_NE(std::string::npos, | |
812 | zero_excluded.find("bloom_filter_full_true_positive = 1@level2")); | |
813 | ASSERT_NE(std::string::npos, | |
814 | zero_excluded.find("block_cache_hit_count = 1@level0, 5@level2")); | |
815 | ASSERT_NE(std::string::npos, | |
816 | zero_excluded.find("block_cache_miss_count = 4@level1, 2@level3")); | |
817 | } | |
818 | ||
819 | TEST_F(PerfContextTest, CPUTimer) { | |
820 | DestroyDB(kDbName, Options()); | |
821 | auto db = OpenDb(); | |
822 | WriteOptions write_options; | |
823 | ReadOptions read_options; | |
824 | SetPerfLevel(PerfLevel::kEnableTimeAndCPUTimeExceptForMutex); | |
825 | ||
826 | std::string max_str = "0"; | |
827 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
828 | std::string i_str = ToString(i); | |
829 | std::string key = "k" + i_str; | |
830 | std::string value = "v" + i_str; | |
831 | max_str = max_str > i_str ? max_str : i_str; | |
832 | ||
833 | db->Put(write_options, key, value); | |
834 | } | |
835 | std::string last_key = "k" + max_str; | |
836 | std::string last_value = "v" + max_str; | |
837 | ||
838 | { | |
839 | // Get | |
840 | get_perf_context()->Reset(); | |
841 | std::string value; | |
842 | ASSERT_OK(db->Get(read_options, "k0", &value)); | |
843 | ASSERT_EQ(value, "v0"); | |
844 | ||
845 | if (FLAGS_verbose) { | |
846 | std::cout << "Get CPU time nanos: " << get_perf_context()->get_cpu_nanos | |
847 | << "ns\n"; | |
848 | } | |
849 | ||
850 | // Iter | |
851 | std::unique_ptr<Iterator> iter(db->NewIterator(read_options)); | |
852 | ||
853 | // Seek | |
854 | get_perf_context()->Reset(); | |
855 | iter->Seek(last_key); | |
856 | ASSERT_TRUE(iter->Valid()); | |
857 | ASSERT_EQ(last_value, iter->value().ToString()); | |
858 | ||
859 | if (FLAGS_verbose) { | |
860 | std::cout << "Iter Seek CPU time nanos: " | |
861 | << get_perf_context()->iter_seek_cpu_nanos << "ns\n"; | |
862 | } | |
863 | ||
864 | // SeekForPrev | |
865 | get_perf_context()->Reset(); | |
866 | iter->SeekForPrev(last_key); | |
867 | ASSERT_TRUE(iter->Valid()); | |
868 | ||
869 | if (FLAGS_verbose) { | |
870 | std::cout << "Iter SeekForPrev CPU time nanos: " | |
871 | << get_perf_context()->iter_seek_cpu_nanos << "ns\n"; | |
872 | } | |
873 | ||
874 | // SeekToLast | |
875 | get_perf_context()->Reset(); | |
876 | iter->SeekToLast(); | |
877 | ASSERT_TRUE(iter->Valid()); | |
878 | ASSERT_EQ(last_value, iter->value().ToString()); | |
879 | ||
880 | if (FLAGS_verbose) { | |
881 | std::cout << "Iter SeekToLast CPU time nanos: " | |
882 | << get_perf_context()->iter_seek_cpu_nanos << "ns\n"; | |
883 | } | |
884 | ||
885 | // SeekToFirst | |
886 | get_perf_context()->Reset(); | |
887 | iter->SeekToFirst(); | |
888 | ASSERT_TRUE(iter->Valid()); | |
889 | ASSERT_EQ("v0", iter->value().ToString()); | |
890 | ||
891 | if (FLAGS_verbose) { | |
892 | std::cout << "Iter SeekToFirst CPU time nanos: " | |
893 | << get_perf_context()->iter_seek_cpu_nanos << "ns\n"; | |
894 | } | |
895 | ||
896 | // Next | |
897 | get_perf_context()->Reset(); | |
898 | iter->Next(); | |
899 | ASSERT_TRUE(iter->Valid()); | |
900 | ASSERT_EQ("v1", iter->value().ToString()); | |
901 | ||
902 | if (FLAGS_verbose) { | |
903 | std::cout << "Iter Next CPU time nanos: " | |
904 | << get_perf_context()->iter_next_cpu_nanos << "ns\n"; | |
905 | } | |
906 | ||
907 | // Prev | |
908 | get_perf_context()->Reset(); | |
909 | iter->Prev(); | |
910 | ASSERT_TRUE(iter->Valid()); | |
911 | ASSERT_EQ("v0", iter->value().ToString()); | |
912 | ||
913 | if (FLAGS_verbose) { | |
914 | std::cout << "Iter Prev CPU time nanos: " | |
915 | << get_perf_context()->iter_prev_cpu_nanos << "ns\n"; | |
916 | } | |
917 | ||
918 | // monotonically increasing | |
919 | get_perf_context()->Reset(); | |
920 | auto count = get_perf_context()->iter_seek_cpu_nanos; | |
921 | for (int i = 0; i < FLAGS_total_keys; ++i) { | |
922 | iter->Seek("k" + ToString(i)); | |
923 | ASSERT_TRUE(iter->Valid()); | |
924 | ASSERT_EQ("v" + ToString(i), iter->value().ToString()); | |
925 | auto next_count = get_perf_context()->iter_seek_cpu_nanos; | |
926 | ASSERT_GT(next_count, count); | |
927 | count = next_count; | |
928 | } | |
929 | ||
930 | // iterator creation/destruction; multiple iterators | |
931 | { | |
932 | std::unique_ptr<Iterator> iter2(db->NewIterator(read_options)); | |
933 | ASSERT_EQ(count, get_perf_context()->iter_seek_cpu_nanos); | |
934 | iter2->Seek(last_key); | |
935 | ASSERT_TRUE(iter2->Valid()); | |
936 | ASSERT_EQ(last_value, iter2->value().ToString()); | |
937 | ASSERT_GT(get_perf_context()->iter_seek_cpu_nanos, count); | |
938 | count = get_perf_context()->iter_seek_cpu_nanos; | |
939 | } | |
940 | ASSERT_EQ(count, get_perf_context()->iter_seek_cpu_nanos); | |
941 | } | |
7c673cae | 942 | } |
f67539c2 | 943 | } // namespace ROCKSDB_NAMESPACE |
7c673cae FG |
944 | |
945 | int main(int argc, char** argv) { | |
946 | ::testing::InitGoogleTest(&argc, argv); | |
947 | ||
948 | for (int i = 1; i < argc; i++) { | |
949 | int n; | |
950 | char junk; | |
951 | ||
952 | if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { | |
953 | FLAGS_write_buffer_size = n; | |
954 | } | |
955 | ||
956 | if (sscanf(argv[i], "--total_keys=%d%c", &n, &junk) == 1) { | |
957 | FLAGS_total_keys = n; | |
958 | } | |
959 | ||
960 | if (sscanf(argv[i], "--random_key=%d%c", &n, &junk) == 1 && | |
961 | (n == 0 || n == 1)) { | |
962 | FLAGS_random_key = n; | |
963 | } | |
964 | ||
965 | if (sscanf(argv[i], "--use_set_based_memetable=%d%c", &n, &junk) == 1 && | |
966 | (n == 0 || n == 1)) { | |
967 | FLAGS_use_set_based_memetable = n; | |
968 | } | |
969 | ||
970 | if (sscanf(argv[i], "--verbose=%d%c", &n, &junk) == 1 && | |
971 | (n == 0 || n == 1)) { | |
972 | FLAGS_verbose = n; | |
973 | } | |
974 | } | |
975 | ||
976 | if (FLAGS_verbose) { | |
977 | std::cout << kDbName << "\n"; | |
978 | } | |
979 | ||
980 | return RUN_ALL_TESTS(); | |
981 | } |