iomgr/timer_heap_test.cc
Go to the documentation of this file.
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 
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 
30 
31 static gpr_atm random_deadline(void) { return rand(); }
32 
34  grpc_timer* elems =
35  static_cast<grpc_timer*>(gpr_malloc(num_elements * sizeof(grpc_timer)));
36  size_t i;
37  for (i = 0; i < num_elements; i++) {
38  elems[i].deadline = random_deadline();
39  }
40  return elems;
41 }
42 
43 static int contains(grpc_timer_heap* pq, grpc_timer* el) {
44  size_t i;
45  for (i = 0; i < pq->timer_count; i++) {
46  if (pq->timers[i] == el) return 1;
47  }
48  return 0;
49 }
50 
51 static void check_valid(grpc_timer_heap* pq) {
52  size_t i;
53  for (i = 0; i < pq->timer_count; ++i) {
54  size_t left_child = 1u + 2u * i;
55  size_t right_child = left_child + 1u;
56  if (left_child < pq->timer_count) {
57  GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[left_child]->deadline);
58  }
59  if (right_child < pq->timer_count) {
60  GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[right_child]->deadline);
61  }
62  }
63 }
64 
65 /*******************************************************************************
66  * test1
67  */
68 
69 static void test1(void) {
70  grpc_timer_heap pq;
71  const size_t num_test_elements = 200;
72  const size_t num_test_operations = 10000;
73  size_t i;
74  grpc_timer* test_elements = create_test_elements(num_test_elements);
75  uint8_t* inpq = static_cast<uint8_t*>(gpr_malloc(num_test_elements));
76 
77  gpr_log(GPR_INFO, "test1");
78 
80  memset(inpq, 0, num_test_elements);
82  check_valid(&pq);
83  for (i = 0; i < num_test_elements; ++i) {
84  GPR_ASSERT(!contains(&pq, &test_elements[i]));
85  grpc_timer_heap_add(&pq, &test_elements[i]);
86  check_valid(&pq);
87  GPR_ASSERT(contains(&pq, &test_elements[i]));
88  inpq[i] = 1;
89  }
90  for (i = 0; i < num_test_elements; ++i) {
91  /* Test that check still succeeds even for element that wasn't just
92  inserted. */
93  GPR_ASSERT(contains(&pq, &test_elements[i]));
94  }
95 
96  GPR_ASSERT(pq.timer_count == num_test_elements);
97 
98  check_valid(&pq);
99 
100  for (i = 0; i < num_test_operations; ++i) {
101  size_t elem_num = static_cast<size_t>(rand()) % num_test_elements;
102  grpc_timer* el = &test_elements[elem_num];
103  if (!inpq[elem_num]) { /* not in pq */
104  GPR_ASSERT(!contains(&pq, el));
105  el->deadline = random_deadline();
106  grpc_timer_heap_add(&pq, el);
107  GPR_ASSERT(contains(&pq, el));
108  inpq[elem_num] = 1;
109  check_valid(&pq);
110  } else {
111  GPR_ASSERT(contains(&pq, el));
112  grpc_timer_heap_remove(&pq, el);
113  GPR_ASSERT(!contains(&pq, el));
114  inpq[elem_num] = 0;
115  check_valid(&pq);
116  }
117  }
118 
120  gpr_free(test_elements);
121  gpr_free(inpq);
122 }
123 
124 /*******************************************************************************
125  * test2
126  */
127 
128 typedef struct {
130  bool inserted;
132 
133 static elem_struct* search_elems(elem_struct* elems, size_t count,
134  bool inserted) {
135  size_t* search_order =
136  static_cast<size_t*>(gpr_malloc(count * sizeof(*search_order)));
137  for (size_t i = 0; i < count; i++) {
138  search_order[i] = i;
139  }
140  for (size_t i = 0; i < count * 2; i++) {
141  size_t a = static_cast<size_t>(rand()) % count;
142  size_t b = static_cast<size_t>(rand()) % count;
143  std::swap(search_order[a], search_order[b]);
144  }
145  elem_struct* out = nullptr;
146  for (size_t i = 0; out == nullptr && i < count; i++) {
147  if (elems[search_order[i]].inserted == inserted) {
148  out = &elems[search_order[i]];
149  }
150  }
151  gpr_free(search_order);
152  return out;
153 }
154 
155 static void test2(void) {
156  gpr_log(GPR_INFO, "test2");
157 
158  grpc_timer_heap pq;
159 
160  static const size_t elems_size = 1000;
161  elem_struct* elems =
162  static_cast<elem_struct*>(gpr_malloc(elems_size * sizeof(elem_struct)));
163  size_t num_inserted = 0;
164 
166  memset(elems, 0, elems_size * sizeof(elems[0]));
167 
168  for (size_t round = 0; round < 10000; round++) {
169  int r = rand() % 1000;
170  if (r <= 550) {
171  /* 55% of the time we try to add something */
172  elem_struct* el = search_elems(elems, elems_size, false);
173  if (el != nullptr) {
174  el->elem.deadline = random_deadline();
175  grpc_timer_heap_add(&pq, &el->elem);
176  el->inserted = true;
177  num_inserted++;
178  check_valid(&pq);
179  }
180  } else if (r <= 650) {
181  /* 10% of the time we try to remove something */
182  elem_struct* el = search_elems(elems, elems_size, true);
183  if (el != nullptr) {
184  grpc_timer_heap_remove(&pq, &el->elem);
185  el->inserted = false;
186  num_inserted--;
187  check_valid(&pq);
188  }
189  } else {
190  /* the remaining times we pop */
191  if (num_inserted > 0) {
193  grpc_timer_heap_pop(&pq);
194  for (size_t i = 0; i < elems_size; i++) {
195  if (top == &elems[i].elem) {
196  GPR_ASSERT(elems[i].inserted);
197  elems[i].inserted = false;
198  }
199  }
200  num_inserted--;
201  check_valid(&pq);
202  }
203  }
204 
205  if (num_inserted) {
206  int64_t* min_deadline = nullptr;
207  for (size_t i = 0; i < elems_size; i++) {
208  if (elems[i].inserted) {
209  if (min_deadline == nullptr) {
210  min_deadline = &elems[i].elem.deadline;
211  } else {
212  if (elems[i].elem.deadline < *min_deadline) {
213  min_deadline = &elems[i].elem.deadline;
214  }
215  }
216  }
217  }
218  GPR_ASSERT(grpc_timer_heap_top(&pq)->deadline == *min_deadline);
219  }
220  }
221 
223  gpr_free(elems);
224 }
225 
226 static void shrink_test(void) {
227  gpr_log(GPR_INFO, "shrink_test");
228 
229  grpc_timer_heap pq;
230  size_t i;
231  size_t expected_size;
232 
233  /* A large random number to allow for multiple shrinkages, at least 512. */
234  const size_t num_elements = static_cast<size_t>(rand()) % 2000 + 512;
235 
237 
238  /* Create a priority queue with many elements. Make sure the Size() is
239  correct. */
240  for (i = 0; i < num_elements; ++i) {
241  GPR_ASSERT(i == pq.timer_count);
243  }
245 
246  /* Remove elements until the Size is 1/4 the original size. */
247  while (pq.timer_count > num_elements / 4) {
248  grpc_timer* const te = pq.timers[pq.timer_count - 1];
249  grpc_timer_heap_remove(&pq, te);
250  gpr_free(te);
251  }
253 
254  /* Expect that Capacity is in the right range:
255  Size * 2 <= Capacity <= Size * 4 */
256  GPR_ASSERT(pq.timer_count * 2 <= pq.timer_capacity);
257  GPR_ASSERT(pq.timer_capacity <= pq.timer_count * 4);
258  check_valid(&pq);
259 
260  /* Remove the rest of the elements. Check that the Capacity is not more than
261  4 times the Size and not less than 2 times, but never goes below 16. */
262  expected_size = pq.timer_count;
263  while (pq.timer_count > 0) {
264  const size_t which = static_cast<size_t>(rand()) % pq.timer_count;
265  grpc_timer* te = pq.timers[which];
266  grpc_timer_heap_remove(&pq, te);
267  gpr_free(te);
268  expected_size--;
269  GPR_ASSERT(expected_size == pq.timer_count);
270  GPR_ASSERT(pq.timer_count * 2 <= pq.timer_capacity);
271  if (pq.timer_count >= 8) {
272  GPR_ASSERT(pq.timer_capacity <= pq.timer_count * 4);
273  } else {
274  GPR_ASSERT(16 <= pq.timer_capacity);
275  }
276  check_valid(&pq);
277  }
278 
279  GPR_ASSERT(0 == pq.timer_count);
280  GPR_ASSERT(pq.timer_capacity >= 16 && pq.timer_capacity < 32);
281 
283 }
284 
285 int main(int argc, char** argv) {
286  int i;
287 
288  grpc::testing::TestEnvironment env(&argc, argv);
289 
290  for (i = 0; i < 5; i++) {
291  test1();
292  test2();
293  shrink_test();
294  }
295 
296  return 0;
297 }
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
elem_struct::inserted
bool inserted
Definition: iomgr/timer_heap_test.cc:132
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
grpc_timer_heap::timers
grpc_timer ** timers
Definition: iomgr/timer_heap.h:27
log.h
generate.env
env
Definition: generate.py:37
main
int main(int argc, char **argv)
Definition: iomgr/timer_heap_test.cc:285
memset
return memset(p, 0, total)
elem_struct
Definition: iomgr/timer_heap_test.cc:128
grpc_timer_heap_remove
void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer)
Definition: iomgr/timer_heap.cc:110
timer_heap.h
string.h
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
useful.h
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
inserted
bool inserted
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:110
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
num_elements
static size_t num_elements(const uint8_t *in, size_t in_len)
Definition: evp_asn1.c:283
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
test2
static void test2(void)
Definition: iomgr/timer_heap_test.cc:155
grpc_timer
Definition: iomgr/timer.h:33
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
grpc_timer_heap_destroy
void grpc_timer_heap_destroy(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:95
grpc_timer_heap_add
bool grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer)
Definition: iomgr/timer_heap.cc:97
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
grpc_timer::deadline
int64_t deadline
Definition: iomgr/timer.h:34
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
search_elems
static elem_struct * search_elems(elem_struct *elems, size_t count, bool inserted)
Definition: iomgr/timer_heap_test.cc:133
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
round
static int round(int n)
Definition: bloaty/third_party/re2/util/benchmark.cc:91
python_utils.jobset.which
def which(filename)
Definition: jobset.py:157
grpc_timer_heap_init
void grpc_timer_heap_init(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:91
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:1226
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
grpc_timer_heap_is_empty
bool grpc_timer_heap_is_empty(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:124
shrink_test
static void shrink_test(void)
Definition: iomgr/timer_heap_test.cc:226
test_config.h
gpr_atm
intptr_t gpr_atm
Definition: impl/codegen/atm_gcc_atomic.h:32
test1
static void test1(void)
Definition: iomgr/timer_heap_test.cc:69
grpc_timer_heap_pop
void grpc_timer_heap_pop(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:132
grpc_timer_heap_top
grpc_timer * grpc_timer_heap_top(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:128
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
port.h
check_valid
static void check_valid(grpc_timer_heap *pq)
Definition: iomgr/timer_heap_test.cc:51
alloc.h
fix_build_deps.r
r
Definition: fix_build_deps.py:491
grpc_timer_heap
Definition: iomgr/timer_heap.h:26
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
grpc_timer_heap::timer_count
uint32_t timer_count
Definition: iomgr/timer_heap.h:28
elem_struct::elem
grpc_timer elem
Definition: iomgr/timer_heap_test.cc:131
grpc_timer_heap::timer_capacity
uint32_t timer_capacity
Definition: iomgr/timer_heap.h:29
contains
static int contains(grpc_timer_heap *pq, grpc_timer *el)
Definition: iomgr/timer_heap_test.cc:43
random_deadline
static gpr_atm random_deadline(void)
Definition: iomgr/timer_heap_test.cc:31
top
static upb_pb_encoder_segment * top(upb_pb_encoder *e)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:7624
create_test_elements
static grpc_timer * create_test_elements(size_t num_elements)
Definition: iomgr/timer_heap_test.cc:33
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:38