You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rspamd_heap_test.c 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "rspamd.h"
  18. #include "heap.h"
  19. #include "ottery.h"
  20. static const unsigned int niter = 100500;
  21. static const unsigned int nrem = 100;
  22. static inline struct rspamd_min_heap_elt *
  23. new_elt(unsigned int pri)
  24. {
  25. struct rspamd_min_heap_elt *elt;
  26. elt = g_slice_alloc0(sizeof(*elt));
  27. elt->pri = pri;
  28. return elt;
  29. }
  30. static double
  31. heap_nelts_test(unsigned int nelts)
  32. {
  33. struct rspamd_min_heap *heap;
  34. struct rspamd_min_heap_elt *elts;
  35. double t1, t2;
  36. unsigned int i;
  37. heap = rspamd_min_heap_create(nelts);
  38. /* Preallocate all elts */
  39. elts = g_slice_alloc(sizeof(*elts) * nelts);
  40. for (i = 0; i < nelts; i++) {
  41. elts[i].pri = ottery_rand_uint32() % G_MAXINT32 + 1;
  42. elts[i].idx = 0;
  43. }
  44. t1 = rspamd_get_virtual_ticks();
  45. for (i = 0; i < nelts; i++) {
  46. rspamd_min_heap_push(heap, &elts[i]);
  47. }
  48. for (i = 0; i < nelts; i++) {
  49. (void) rspamd_min_heap_pop(heap);
  50. }
  51. t2 = rspamd_get_virtual_ticks();
  52. g_slice_free1(sizeof(*elts) * nelts, elts);
  53. rspamd_min_heap_destroy(heap);
  54. return (t2 - t1);
  55. }
  56. void rspamd_heap_test_func(void)
  57. {
  58. struct rspamd_min_heap *heap;
  59. struct rspamd_min_heap_elt *elt, *telt;
  60. unsigned int i;
  61. unsigned int prev;
  62. double t[16];
  63. /* Push + update */
  64. heap = rspamd_min_heap_create(32);
  65. elt = new_elt(2);
  66. elt->data = GINT_TO_POINTER(1);
  67. rspamd_min_heap_push(heap, elt);
  68. elt = new_elt(3);
  69. elt->data = GINT_TO_POINTER(2);
  70. rspamd_min_heap_push(heap, elt);
  71. elt = new_elt(4);
  72. elt->data = GINT_TO_POINTER(3);
  73. rspamd_min_heap_push(heap, elt);
  74. rspamd_min_heap_update_elt(heap, elt, 0);
  75. elt = rspamd_min_heap_pop(heap);
  76. g_assert(elt->data == GINT_TO_POINTER(3));
  77. rspamd_min_heap_destroy(heap);
  78. /* Push + remove */
  79. heap = rspamd_min_heap_create(32);
  80. elt = new_elt(2);
  81. elt->data = GINT_TO_POINTER(1);
  82. rspamd_min_heap_push(heap, elt);
  83. rspamd_min_heap_remove_elt(heap, elt);
  84. elt = new_elt(3);
  85. elt->data = GINT_TO_POINTER(2);
  86. rspamd_min_heap_push(heap, elt);
  87. elt = rspamd_min_heap_pop(heap);
  88. g_assert(elt->data == GINT_TO_POINTER(2));
  89. elt = rspamd_min_heap_pop(heap);
  90. g_assert(elt == NULL);
  91. /* Push + push + remove + pop */
  92. elt = new_elt(2);
  93. elt->data = GINT_TO_POINTER(1);
  94. rspamd_min_heap_push(heap, elt);
  95. telt = elt;
  96. elt = new_elt(3);
  97. elt->data = GINT_TO_POINTER(2);
  98. rspamd_min_heap_push(heap, elt);
  99. rspamd_min_heap_remove_elt(heap, telt);
  100. elt = rspamd_min_heap_pop(heap);
  101. g_assert(elt->data == GINT_TO_POINTER(2));
  102. rspamd_min_heap_destroy(heap);
  103. /* Bulk test */
  104. heap = rspamd_min_heap_create(32);
  105. for (i = 100; i > 0; i--) {
  106. elt = new_elt(i - 1);
  107. rspamd_min_heap_push(heap, elt);
  108. }
  109. for (i = 0; i < 100; i++) {
  110. elt = rspamd_min_heap_pop(heap);
  111. g_assert(elt->pri == i);
  112. }
  113. rspamd_min_heap_destroy(heap);
  114. /* Fuzz test */
  115. heap = rspamd_min_heap_create(128);
  116. /* Add */
  117. for (i = 0; i < niter; i++) {
  118. elt = new_elt(ottery_rand_uint32() % G_MAXINT32 + 1);
  119. rspamd_min_heap_push(heap, elt);
  120. }
  121. /* Remove */
  122. for (i = 0; i < nrem; i++) {
  123. elt = rspamd_min_heap_index(heap, ottery_rand_uint32() % niter);
  124. rspamd_min_heap_remove_elt(heap, elt);
  125. }
  126. /* Update */
  127. for (i = 0; i < niter / 10; i++) {
  128. elt = rspamd_min_heap_index(heap, ottery_rand_uint32() % (niter - nrem));
  129. rspamd_min_heap_update_elt(heap, elt,
  130. ottery_rand_uint32() % G_MAXINT32 + 1);
  131. }
  132. prev = 0;
  133. /* Pop and check invariant */
  134. for (i = 0; i < niter - nrem; i++) {
  135. elt = rspamd_min_heap_pop(heap);
  136. if (prev != 0) {
  137. g_assert(elt->pri >= prev);
  138. }
  139. prev = elt->pri;
  140. }
  141. rspamd_min_heap_destroy(heap);
  142. /* Complexity test (should be O(n * logn) */
  143. for (i = 1; i <= G_N_ELEMENTS(t); i++) {
  144. t[i - 1] = heap_nelts_test(0x1 << (i + 4));
  145. }
  146. for (i = 1; i <= G_N_ELEMENTS(t); i++) {
  147. rspamd_printf("Elements: %d, time: %.4f\n", 0x1 << (i + 4), t[i - 1]);
  148. }
  149. }