timer_heap_test.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. #include "src/core/lib/iomgr/timer_heap.h"
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <grpc/support/alloc.h>
  22. #include <grpc/support/log.h>
  23. #include "src/core/lib/gpr/useful.h"
  24. #include "src/core/lib/iomgr/port.h"
  25. #include "test/core/util/test_config.h"
  26. static gpr_atm random_deadline(void) { return rand(); }
  27. static grpc_timer* create_test_elements(size_t num_elements) {
  28. grpc_timer* elems =
  29. static_cast<grpc_timer*>(gpr_malloc(num_elements * sizeof(grpc_timer)));
  30. size_t i;
  31. for (i = 0; i < num_elements; i++) {
  32. elems[i].deadline = random_deadline();
  33. }
  34. return elems;
  35. }
  36. static int contains(grpc_timer_heap* pq, grpc_timer* el) {
  37. size_t i;
  38. for (i = 0; i < pq->timer_count; i++) {
  39. if (pq->timers[i] == el) return 1;
  40. }
  41. return 0;
  42. }
  43. static void check_valid(grpc_timer_heap* pq) {
  44. size_t i;
  45. for (i = 0; i < pq->timer_count; ++i) {
  46. size_t left_child = 1u + 2u * i;
  47. size_t right_child = left_child + 1u;
  48. if (left_child < pq->timer_count) {
  49. GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[left_child]->deadline);
  50. }
  51. if (right_child < pq->timer_count) {
  52. GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[right_child]->deadline);
  53. }
  54. }
  55. }
  56. /*******************************************************************************
  57. * test1
  58. */
  59. static void test1(void) {
  60. grpc_timer_heap pq;
  61. const size_t num_test_elements = 200;
  62. const size_t num_test_operations = 10000;
  63. size_t i;
  64. grpc_timer* test_elements = create_test_elements(num_test_elements);
  65. uint8_t* inpq = static_cast<uint8_t*>(gpr_malloc(num_test_elements));
  66. gpr_log(GPR_INFO, "test1");
  67. grpc_timer_heap_init(&pq);
  68. memset(inpq, 0, num_test_elements);
  69. GPR_ASSERT(grpc_timer_heap_is_empty(&pq));
  70. check_valid(&pq);
  71. for (i = 0; i < num_test_elements; ++i) {
  72. GPR_ASSERT(!contains(&pq, &test_elements[i]));
  73. grpc_timer_heap_add(&pq, &test_elements[i]);
  74. check_valid(&pq);
  75. GPR_ASSERT(contains(&pq, &test_elements[i]));
  76. inpq[i] = 1;
  77. }
  78. for (i = 0; i < num_test_elements; ++i) {
  79. /* Test that check still succeeds even for element that wasn't just
  80. inserted. */
  81. GPR_ASSERT(contains(&pq, &test_elements[i]));
  82. }
  83. GPR_ASSERT(pq.timer_count == num_test_elements);
  84. check_valid(&pq);
  85. for (i = 0; i < num_test_operations; ++i) {
  86. size_t elem_num = static_cast<size_t>(rand()) % num_test_elements;
  87. grpc_timer* el = &test_elements[elem_num];
  88. if (!inpq[elem_num]) { /* not in pq */
  89. GPR_ASSERT(!contains(&pq, el));
  90. el->deadline = random_deadline();
  91. grpc_timer_heap_add(&pq, el);
  92. GPR_ASSERT(contains(&pq, el));
  93. inpq[elem_num] = 1;
  94. check_valid(&pq);
  95. } else {
  96. GPR_ASSERT(contains(&pq, el));
  97. grpc_timer_heap_remove(&pq, el);
  98. GPR_ASSERT(!contains(&pq, el));
  99. inpq[elem_num] = 0;
  100. check_valid(&pq);
  101. }
  102. }
  103. grpc_timer_heap_destroy(&pq);
  104. gpr_free(test_elements);
  105. gpr_free(inpq);
  106. }
  107. /*******************************************************************************
  108. * test2
  109. */
  110. typedef struct {
  111. grpc_timer elem;
  112. bool inserted;
  113. } elem_struct;
  114. static elem_struct* search_elems(elem_struct* elems, size_t count,
  115. bool inserted) {
  116. size_t* search_order =
  117. static_cast<size_t*>(gpr_malloc(count * sizeof(*search_order)));
  118. for (size_t i = 0; i < count; i++) {
  119. search_order[i] = i;
  120. }
  121. for (size_t i = 0; i < count * 2; i++) {
  122. size_t a = static_cast<size_t>(rand()) % count;
  123. size_t b = static_cast<size_t>(rand()) % count;
  124. std::swap(search_order[a], search_order[b]);
  125. }
  126. elem_struct* out = nullptr;
  127. for (size_t i = 0; out == nullptr && i < count; i++) {
  128. if (elems[search_order[i]].inserted == inserted) {
  129. out = &elems[search_order[i]];
  130. }
  131. }
  132. gpr_free(search_order);
  133. return out;
  134. }
  135. static void test2(void) {
  136. gpr_log(GPR_INFO, "test2");
  137. grpc_timer_heap pq;
  138. static const size_t elems_size = 1000;
  139. elem_struct* elems =
  140. static_cast<elem_struct*>(gpr_malloc(elems_size * sizeof(elem_struct)));
  141. size_t num_inserted = 0;
  142. grpc_timer_heap_init(&pq);
  143. memset(elems, 0, elems_size * sizeof(elems[0]));
  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. elem_struct* el = search_elems(elems, elems_size, false);
  149. if (el != nullptr) {
  150. el->elem.deadline = random_deadline();
  151. grpc_timer_heap_add(&pq, &el->elem);
  152. el->inserted = true;
  153. num_inserted++;
  154. check_valid(&pq);
  155. }
  156. } else if (r <= 650) {
  157. /* 10% of the time we try to remove something */
  158. elem_struct* el = search_elems(elems, elems_size, true);
  159. if (el != nullptr) {
  160. grpc_timer_heap_remove(&pq, &el->elem);
  161. el->inserted = false;
  162. num_inserted--;
  163. check_valid(&pq);
  164. }
  165. } else {
  166. /* the remaining times we pop */
  167. if (num_inserted > 0) {
  168. grpc_timer* top = grpc_timer_heap_top(&pq);
  169. grpc_timer_heap_pop(&pq);
  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. check_valid(&pq);
  178. }
  179. }
  180. if (num_inserted) {
  181. int64_t* min_deadline = nullptr;
  182. for (size_t i = 0; i < elems_size; i++) {
  183. if (elems[i].inserted) {
  184. if (min_deadline == nullptr) {
  185. min_deadline = &elems[i].elem.deadline;
  186. } else {
  187. if (elems[i].elem.deadline < *min_deadline) {
  188. min_deadline = &elems[i].elem.deadline;
  189. }
  190. }
  191. }
  192. }
  193. GPR_ASSERT(grpc_timer_heap_top(&pq)->deadline == *min_deadline);
  194. }
  195. }
  196. grpc_timer_heap_destroy(&pq);
  197. gpr_free(elems);
  198. }
  199. static void shrink_test(void) {
  200. gpr_log(GPR_INFO, "shrink_test");
  201. grpc_timer_heap pq;
  202. size_t i;
  203. size_t expected_size;
  204. /* A large random number to allow for multiple shrinkages, at least 512. */
  205. const size_t num_elements = static_cast<size_t>(rand()) % 2000 + 512;
  206. grpc_timer_heap_init(&pq);
  207. /* Create a priority queue with many elements. Make sure the Size() is
  208. correct. */
  209. for (i = 0; i < num_elements; ++i) {
  210. GPR_ASSERT(i == pq.timer_count);
  211. grpc_timer_heap_add(&pq, create_test_elements(1));
  212. }
  213. GPR_ASSERT(num_elements == pq.timer_count);
  214. /* Remove elements until the Size is 1/4 the original size. */
  215. while (pq.timer_count > num_elements / 4) {
  216. grpc_timer* const te = pq.timers[pq.timer_count - 1];
  217. grpc_timer_heap_remove(&pq, te);
  218. gpr_free(te);
  219. }
  220. GPR_ASSERT(num_elements / 4 == pq.timer_count);
  221. /* Expect that Capacity is in the right range:
  222. Size * 2 <= Capacity <= Size * 4 */
  223. GPR_ASSERT(pq.timer_count * 2 <= pq.timer_capacity);
  224. GPR_ASSERT(pq.timer_capacity <= pq.timer_count * 4);
  225. check_valid(&pq);
  226. /* Remove the rest of the elements. Check that the Capacity is not more than
  227. 4 times the Size and not less than 2 times, but never goes below 16. */
  228. expected_size = pq.timer_count;
  229. while (pq.timer_count > 0) {
  230. const size_t which = static_cast<size_t>(rand()) % pq.timer_count;
  231. grpc_timer* te = pq.timers[which];
  232. grpc_timer_heap_remove(&pq, te);
  233. gpr_free(te);
  234. expected_size--;
  235. GPR_ASSERT(expected_size == pq.timer_count);
  236. GPR_ASSERT(pq.timer_count * 2 <= pq.timer_capacity);
  237. if (pq.timer_count >= 8) {
  238. GPR_ASSERT(pq.timer_capacity <= pq.timer_count * 4);
  239. } else {
  240. GPR_ASSERT(16 <= pq.timer_capacity);
  241. }
  242. check_valid(&pq);
  243. }
  244. GPR_ASSERT(0 == pq.timer_count);
  245. GPR_ASSERT(pq.timer_capacity >= 16 && pq.timer_capacity < 32);
  246. grpc_timer_heap_destroy(&pq);
  247. }
  248. int main(int argc, char** argv) {
  249. int i;
  250. grpc::testing::TestEnvironment env(argc, argv);
  251. for (i = 0; i < 5; i++) {
  252. test1();
  253. test2();
  254. shrink_test();
  255. }
  256. return 0;
  257. }