|
29 | 29 |
|
30 | 30 | namespace bustub {
|
31 | 31 |
|
32 |
| -bool BPlusTreeLockBenchmarkCall(size_t num_threads, int leaf_node_size, bool with_global_mutex) { |
33 |
| - bool success = true; |
34 |
| - std::vector<int64_t> insert_keys; |
35 |
| - |
| 32 | +size_t BPlusTreeLockBenchmarkCall(size_t num_threads, bool with_global_mutex) { |
36 | 33 | // create KeyComparator and index schema
|
37 | 34 | auto key_schema = ParseCreateStatement("a bigint");
|
38 | 35 | GenericComparator<8> comparator(key_schema.get());
|
39 |
| - auto *disk_manager = new DiskManagerMemory(256 << 10); // 1GB |
40 |
| - auto *bpm = new BufferPoolManager(64, disk_manager); |
| 36 | + |
| 37 | + // create lightweight BPM |
| 38 | + const size_t bpm_size = 256 << 10; // 1GB |
| 39 | + DiskManagerMemory disk_manager(bpm_size); |
| 40 | + BufferPoolManager bpm(bpm_size, &disk_manager); |
41 | 41 |
|
42 | 42 | // allocate header_page
|
43 |
| - page_id_t page_id = bpm->NewPage(); |
| 43 | + page_id_t page_id = bpm.NewPage(); |
44 | 44 |
|
45 | 45 | // create b+ tree
|
46 |
| - BPlusTree<GenericKey<8>, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, leaf_node_size, 10); |
| 46 | + const int node_size = 20; |
| 47 | + BPlusTree<GenericKey<8>, RID, GenericComparator<8>> tree("foo_pk", page_id, &bpm, comparator, node_size, node_size); |
47 | 48 |
|
48 | 49 | std::vector<std::thread> threads;
|
49 | 50 |
|
50 |
| - const int keys_per_thread = 20000 / num_threads; |
51 |
| - const int keys_stride = 100000; |
| 51 | + const int keys_per_stride = 160000 / num_threads; |
| 52 | + const int key_stride = 6400000; |
52 | 53 | std::mutex mtx;
|
53 | 54 |
|
54 |
| - for (size_t i = 0; i < num_threads; i++) { |
55 |
| - auto func = [&tree, &mtx, i, keys_per_thread, with_global_mutex]() { |
56 |
| - GenericKey<8> index_key; |
57 |
| - RID rid; |
58 |
| - const auto end_key = keys_stride * i + keys_per_thread; |
59 |
| - for (auto key = i * keys_stride; key < end_key; key++) { |
60 |
| - int64_t value = key & 0xFFFFFFFF; |
61 |
| - rid.Set(static_cast<int32_t>(key >> 32), value); |
62 |
| - index_key.SetFromInteger(key); |
63 |
| - if (with_global_mutex) { |
64 |
| - mtx.lock(); |
65 |
| - } |
66 |
| - tree.Insert(index_key, rid); |
67 |
| - if (with_global_mutex) { |
68 |
| - mtx.unlock(); |
69 |
| - } |
| 55 | + auto insert_keys = [&](const int64_t start_key, const int64_t end_key) { |
| 56 | + GenericKey<8> index_key; |
| 57 | + RID rid; |
| 58 | + for (auto key = start_key; key < end_key; key++) { |
| 59 | + int64_t value = key & 0xFFFFFFFF; |
| 60 | + rid.Set(static_cast<int32_t>(key >> 32), value); |
| 61 | + index_key.SetFromInteger(key); |
| 62 | + if (with_global_mutex) { |
| 63 | + mtx.lock(); |
70 | 64 | }
|
71 |
| - }; |
72 |
| - auto t = std::thread(std::move(func)); |
73 |
| - threads.emplace_back(std::move(t)); |
74 |
| - } |
| 65 | + tree.Insert(index_key, rid); |
| 66 | + if (with_global_mutex) { |
| 67 | + mtx.unlock(); |
| 68 | + } |
| 69 | + } |
| 70 | + }; |
75 | 71 |
|
| 72 | + // Measure |
| 73 | + auto start_time = std::chrono::system_clock::now(); |
| 74 | + for (size_t i = 0; i < num_threads; i++) { |
| 75 | + const auto start_key = i * key_stride; |
| 76 | + threads.emplace_back(insert_keys, start_key, start_key + keys_per_stride); |
| 77 | + } |
76 | 78 | for (auto &thread : threads) {
|
77 | 79 | thread.join();
|
78 | 80 | }
|
| 81 | + auto end_time = std::chrono::system_clock::now(); |
79 | 82 |
|
80 |
| - delete disk_manager; |
81 |
| - delete bpm; |
82 |
| - |
83 |
| - return success; |
| 83 | + return std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count(); |
84 | 84 | }
|
85 | 85 |
|
86 | 86 | TEST(BPlusTreeContentionTest, BPlusTreeContentionBenchmark) { // NOLINT
|
87 | 87 | std::cout << "This test will see how your B+ tree performance differs with and without contention." << std::endl;
|
88 | 88 | std::cout << "If your submission timeout, segfault, or didn't implement lock crabbing, we will manually deduct all "
|
89 | 89 | "concurrent test points (maximum 25)."
|
90 | 90 | << std::endl;
|
91 |
| - std::cout << "left_node_size = 2" << std::endl; |
92 | 91 |
|
93 | 92 | std::vector<size_t> time_ms_with_mutex;
|
94 | 93 | std::vector<size_t> time_ms_wo_mutex;
|
95 |
| - for (size_t iter = 0; iter < 20; iter++) { |
| 94 | + for (size_t iter = 0; iter < 10; iter++) { |
96 | 95 | bool enable_mutex = iter % 2 == 0;
|
97 |
| - auto clock_start = std::chrono::system_clock::now(); |
98 |
| - ASSERT_TRUE(BPlusTreeLockBenchmarkCall(32, 2, enable_mutex)); |
99 |
| - auto clock_end = std::chrono::system_clock::now(); |
100 |
| - auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(clock_end - clock_start); |
| 96 | + auto time = BPlusTreeLockBenchmarkCall(4, enable_mutex); |
101 | 97 | if (enable_mutex) {
|
102 |
| - time_ms_with_mutex.push_back(dur.count()); |
| 98 | + time_ms_with_mutex.push_back(time); |
103 | 99 | } else {
|
104 |
| - time_ms_wo_mutex.push_back(dur.count()); |
| 100 | + time_ms_wo_mutex.push_back(time); |
105 | 101 | }
|
106 | 102 | }
|
107 | 103 |
|
108 | 104 | std::cout << "<<< BEGIN" << std::endl;
|
109 |
| - std::cout << "Normal Access Time: "; |
110 |
| - double ratio_1 = 0; |
111 |
| - double ratio_2 = 0; |
| 105 | + std::cout << "Multithreaded Access Time: "; |
| 106 | + double sum_1 = 0; |
| 107 | + double sum_2 = 0; |
112 | 108 | for (auto x : time_ms_wo_mutex) {
|
113 | 109 | std::cout << x << " ";
|
114 |
| - ratio_1 += x; |
| 110 | + sum_1 += x; |
115 | 111 | }
|
116 | 112 | std::cout << std::endl;
|
117 | 113 |
|
118 | 114 | std::cout << "Serialized Access Time: ";
|
119 | 115 | for (auto x : time_ms_with_mutex) {
|
120 | 116 | std::cout << x << " ";
|
121 |
| - ratio_2 += x; |
| 117 | + sum_2 += x; |
122 | 118 | }
|
123 | 119 | std::cout << std::endl;
|
124 |
| - std::cout << "Ratio: " << ratio_1 / ratio_2 << std::endl; |
| 120 | + double speedup = sum_2 / sum_1; |
| 121 | + std::cout << "Speedup: " << speedup << std::endl; |
125 | 122 | std::cout << ">>> END" << std::endl;
|
126 | 123 | std::cout << "If your above data is an outlier in all submissions (based on statistics and probably some "
|
127 | 124 | "machine-learning), TAs will manually inspect your code to ensure you are implementing lock crabbing "
|
128 | 125 | "correctly."
|
129 | 126 | << std::endl;
|
130 | 127 | }
|
131 | 128 |
|
132 |
| -TEST(BPlusTreeContentionTest, BPlusTreeContentionBenchmark2) { // NOLINT |
133 |
| - std::cout << "This test will see how your B+ tree performance differs with and without contention." << std::endl; |
134 |
| - std::cout << "If your submission timeout, segfault, or didn't implement lock crabbing, we will manually deduct all " |
135 |
| - "concurrent test points (maximum 25)." |
136 |
| - << std::endl; |
137 |
| - std::cout << "left_node_size = 10" << std::endl; |
138 |
| - |
139 |
| - std::vector<size_t> time_ms_with_mutex; |
140 |
| - std::vector<size_t> time_ms_wo_mutex; |
141 |
| - for (size_t iter = 0; iter < 20; iter++) { |
142 |
| - bool enable_mutex = iter % 2 == 0; |
143 |
| - auto clock_start = std::chrono::system_clock::now(); |
144 |
| - ASSERT_TRUE(BPlusTreeLockBenchmarkCall(32, 10, enable_mutex)); |
145 |
| - auto clock_end = std::chrono::system_clock::now(); |
146 |
| - auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(clock_end - clock_start); |
147 |
| - if (enable_mutex) { |
148 |
| - time_ms_with_mutex.push_back(dur.count()); |
149 |
| - } else { |
150 |
| - time_ms_wo_mutex.push_back(dur.count()); |
151 |
| - } |
152 |
| - } |
153 |
| - |
154 |
| - std::cout << "<<< BEGIN2" << std::endl; |
155 |
| - std::cout << "Normal Access Time: "; |
156 |
| - double ratio_1 = 0; |
157 |
| - double ratio_2 = 0; |
158 |
| - for (auto x : time_ms_wo_mutex) { |
159 |
| - std::cout << x << " "; |
160 |
| - ratio_1 += x; |
161 |
| - } |
162 |
| - std::cout << std::endl; |
163 |
| - |
164 |
| - std::cout << "Serialized Access Time: "; |
165 |
| - for (auto x : time_ms_with_mutex) { |
166 |
| - std::cout << x << " "; |
167 |
| - ratio_2 += x; |
168 |
| - } |
169 |
| - std::cout << std::endl; |
170 |
| - std::cout << "Ratio: " << ratio_1 / ratio_2 << std::endl; |
171 |
| - std::cout << ">>> END2" << std::endl; |
172 |
| - std::cout << "If your above data is an outlier in all submissions (based on statistics and probably some " |
173 |
| - "machine-learning), TAs will manually inspect your code to ensure you are implementing lock crabbing " |
174 |
| - "correctly." |
175 |
| - << std::endl; |
176 |
| -} |
177 |
| - |
178 | 129 | } // namespace bustub
|
0 commit comments