1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/lib/event_engine/posix_engine/timer_heap.h"
20
21 #include <stdint.h>
22 #include <stdlib.h>
23
24 #include <algorithm>
25 #include <utility>
26
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29
30 #include <grpc/support/log.h>
31
32 #include "src/core/lib/event_engine/posix_engine/timer.h"
33 #include "src/core/lib/gprpp/bitset.h"
34
35 using testing::Contains;
36 using testing::Not;
37
38 namespace grpc_event_engine {
39 namespace experimental {
40
41 namespace {
RandomDeadline(void)42 int64_t RandomDeadline(void) { return rand(); }
43
CreateTestElements(size_t num_elements)44 std::vector<Timer> CreateTestElements(size_t num_elements) {
45 std::vector<Timer> elems(num_elements);
46 for (size_t i = 0; i < num_elements; i++) {
47 elems[i].deadline = RandomDeadline();
48 }
49 return elems;
50 }
51
CheckValid(TimerHeap * pq)52 void CheckValid(TimerHeap* pq) {
53 const std::vector<Timer*>& timers = pq->TestOnlyGetTimers();
54 for (size_t i = 0; i < timers.size(); ++i) {
55 size_t left_child = 1u + 2u * i;
56 size_t right_child = left_child + 1u;
57 if (left_child < timers.size()) {
58 EXPECT_LE(timers[i]->deadline, timers[left_child]->deadline);
59 }
60 if (right_child < timers.size()) {
61 EXPECT_LE(timers[i]->deadline, timers[right_child]->deadline);
62 }
63 }
64 }
65
TEST(TimerHeapTest,Basics)66 TEST(TimerHeapTest, Basics) {
67 TimerHeap pq;
68 const size_t num_test_elements = 200;
69 const size_t num_test_operations = 10000;
70 size_t i;
71 std::vector<Timer> test_elements = CreateTestElements(num_test_elements);
72 grpc_core::BitSet<num_test_elements> inpq;
73
74 EXPECT_TRUE(pq.is_empty());
75 CheckValid(&pq);
76 for (i = 0; i < num_test_elements; ++i) {
77 EXPECT_THAT(pq.TestOnlyGetTimers(), Not(Contains(&test_elements[i])));
78 pq.Add(&test_elements[i]);
79 CheckValid(&pq);
80 EXPECT_THAT(pq.TestOnlyGetTimers(), Contains(&test_elements[i]));
81 inpq.set(i);
82 }
83 for (i = 0; i < num_test_elements; ++i) {
84 // Test that check still succeeds even for element that wasn't just
85 // inserted.
86 EXPECT_THAT(pq.TestOnlyGetTimers(), Contains(&test_elements[i]));
87 }
88
89 EXPECT_EQ(pq.TestOnlyGetTimers().size(), num_test_elements);
90 CheckValid(&pq);
91
92 for (i = 0; i < num_test_operations; ++i) {
93 size_t elem_num = static_cast<size_t>(rand()) % num_test_elements;
94 Timer* el = &test_elements[elem_num];
95 if (!inpq.is_set(elem_num)) { // not in pq
96 EXPECT_THAT(pq.TestOnlyGetTimers(), Not(Contains(el)));
97 el->deadline = RandomDeadline();
98 pq.Add(el);
99 EXPECT_THAT(pq.TestOnlyGetTimers(), Contains(el));
100 inpq.set(elem_num);
101 CheckValid(&pq);
102 } else {
103 EXPECT_THAT(pq.TestOnlyGetTimers(), Contains(el));
104 pq.Remove(el);
105 EXPECT_THAT(pq.TestOnlyGetTimers(), Not(Contains(el)));
106 inpq.clear(elem_num);
107 CheckValid(&pq);
108 }
109 }
110 }
111
112 struct ElemStruct {
113 Timer elem;
114 bool inserted = false;
115 };
116
SearchElems(std::vector<ElemStruct> & elems,bool inserted)117 ElemStruct* SearchElems(std::vector<ElemStruct>& elems, bool inserted) {
118 std::vector<size_t> search_order;
119 for (size_t i = 0; i < elems.size(); i++) {
120 search_order.push_back(i);
121 }
122 for (size_t i = 0; i < elems.size() * 2; i++) {
123 size_t a = static_cast<size_t>(rand()) % elems.size();
124 size_t b = static_cast<size_t>(rand()) % elems.size();
125 std::swap(search_order[a], search_order[b]);
126 }
127 ElemStruct* out = nullptr;
128 for (size_t i = 0; out == nullptr && i < elems.size(); i++) {
129 if (elems[search_order[i]].inserted == inserted) {
130 out = &elems[search_order[i]];
131 }
132 }
133 return out;
134 }
135
136 // TODO(ctiller): this should be an actual fuzzer
TEST(TimerHeapTest,RandomMutations)137 TEST(TimerHeapTest, RandomMutations) {
138 TimerHeap pq;
139
140 static const size_t elems_size = 1000;
141 std::vector<ElemStruct> elems(elems_size);
142 size_t num_inserted = 0;
143
144 for (size_t round = 0; round < 10000; round++) {
145 int r = rand() % 1000;
146 if (r <= 550) {
147 // 55% of the time we try to add something
148 ElemStruct* el = SearchElems(elems, false);
149 if (el != nullptr) {
150 el->elem.deadline = RandomDeadline();
151 pq.Add(&el->elem);
152 el->inserted = true;
153 num_inserted++;
154 CheckValid(&pq);
155 }
156 } else if (r <= 650) {
157 // 10% of the time we try to remove something
158 ElemStruct* el = SearchElems(elems, true);
159 if (el != nullptr) {
160 pq.Remove(&el->elem);
161 el->inserted = false;
162 num_inserted--;
163 CheckValid(&pq);
164 }
165 } else {
166 // the remaining times we pop
167 if (num_inserted > 0) {
168 Timer* top = pq.Top();
169 pq.Pop();
170 for (size_t i = 0; i < elems_size; i++) {
171 if (top == &elems[i].elem) {
172 GPR_ASSERT(elems[i].inserted);
173 elems[i].inserted = false;
174 }
175 }
176 num_inserted--;
177 CheckValid(&pq);
178 }
179 }
180
181 if (num_inserted) {
182 int64_t* min_deadline = nullptr;
183 for (size_t i = 0; i < elems_size; i++) {
184 if (elems[i].inserted) {
185 if (min_deadline == nullptr) {
186 min_deadline = &elems[i].elem.deadline;
187 } else {
188 if (elems[i].elem.deadline < *min_deadline) {
189 min_deadline = &elems[i].elem.deadline;
190 }
191 }
192 }
193 }
194 GPR_ASSERT(pq.Top()->deadline == *min_deadline);
195 }
196 }
197 }
198
199 } // namespace
200 } // namespace experimental
201 } // namespace grpc_event_engine
202
main(int argc,char ** argv)203 int main(int argc, char** argv) {
204 ::testing::InitGoogleTest(&argc, argv);
205 return RUN_ALL_TESTS();
206 }
207