The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
lst_tests.c
Go to the documentation of this file.
1 #include <freeradius-devel/util/acutest.h>
2 #include <freeradius-devel/util/acutest_helpers.h>
3 #include <freeradius-devel/util/rand.h>
4 #include <freeradius-devel/util/time.h>
5 #include <freeradius-devel/util/heap.h>
6 
7 /*
8  * This counterintuitive #include gives these separately-compiled tests
9  * access to fr_lst_t internals that lst.h doesn't reveal
10  * to those who #include it.
11  */
12 #include "lst.c"
13 
14 typedef struct {
15  unsigned int data;
17  bool visited; /* Only used by iterator test */
18 } lst_thing;
19 
20 #if 0
21 static void lst_validate(fr_lst_t *lst);
22 #endif
23 
24 static bool fr_lst_contains(fr_lst_t *lst, void *data)
25 {
26  unsigned int size = fr_lst_num_elements(lst);
27 
28  for (unsigned int i = 0; i < size; i++) if (item(lst, i + lst->idx) == data) return true;
29 
30  return false;
31 }
32 
33 static int8_t lst_cmp(void const *one, void const *two)
34 {
35  lst_thing const *item1 = one, *item2 = two;
36 
37  return CMP(item1->data, item2->data);
38 }
39 
40 static void populate_values(lst_thing values[], unsigned int len)
41 {
42  unsigned int i;
43  fr_fast_rand_t rand_ctx;
44 
45  for (i = 0; i < len; i++) {
46  values[i].data = i;
47  values[i].idx = 0;
48  values[i].visited = false;
49  }
50 
51  /* shuffle values before insertion, so the heap has to work to give them back in order */
52  rand_ctx.a = fr_rand();
53  rand_ctx.b = fr_rand();
54 
55  for (i = 0; i < len; i++) {
56  unsigned int j = fr_fast_rand(&rand_ctx) % len;
57  int temp = values[i].data;
58 
59  values[i].data = values[j].data;
60  values[j].data = temp;
61  }
62 }
63 
64 #define NVALUES 20
65 static void lst_test_basic(void)
66 {
67  fr_lst_t *lst;
68  lst_thing values[NVALUES];
69 
70  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, NVALUES);
71  TEST_CHECK(lst != NULL);
72 
73  populate_values(values, NUM_ELEMENTS(values));
74 
75  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) {
76  TEST_CHECK(fr_lst_insert(lst, &values[i]) >= 0);
77  TEST_CHECK(fr_lst_entry_inserted(values[i].idx));
78  }
79 
80  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) {
81  lst_thing *value = fr_lst_pop(lst);
82 
83  TEST_CHECK(value != NULL);
85  TEST_CHECK(value->data == i);
86  TEST_MSG("iteration %u, popped %u", i, value->data);
87  }
88  talloc_free(lst);
89 }
90 
91 #define LST_TEST_SIZE (4096)
92 
93 static void lst_test(int skip)
94 {
95  fr_lst_t *lst;
96  unsigned int i;
97  lst_thing *values;
98  unsigned int left;
99  int ret;
100 
101  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
102  TEST_CHECK(lst != NULL);
103 
104  values = calloc(LST_TEST_SIZE, sizeof(lst_thing));
105 
106  /*
107  * Initialise random values
108  */
110 
111  TEST_CASE("insertions");
112  for (i = 0; i < LST_TEST_SIZE; i++) {
113  FR_LST_VERIFY(lst);
114  TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
115  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
116 
117  TEST_CHECK(fr_lst_contains(lst, &values[i]));
118  TEST_MSG("element %i inserted but not in LST", i);
119  }
120 
121  TEST_CASE("deletions");
122  for (int entry = 0; entry < LST_TEST_SIZE; entry += skip) {
123  FR_LST_VERIFY(lst);
124  TEST_CHECK(values[entry].idx != 0);
125  TEST_MSG("element %i removed out of order", entry);
126 
127  TEST_CHECK((ret = fr_lst_extract(lst, &values[entry])) >= 0);
128  TEST_MSG("element %i removal failed, returned %i", entry, ret);
129 
130  TEST_CHECK(!fr_lst_contains(lst, &values[entry]));
131  TEST_MSG("element %i removed but still in LST", entry);
132 
133  TEST_CHECK(values[entry].idx == 0);
134  TEST_MSG("element %i removed out of order", entry);
135  }
136 
137  left = fr_lst_num_elements(lst);
138  for (i = 0; i < left; i++) {
139  FR_LST_VERIFY(lst);
140  TEST_CHECK(fr_lst_pop(lst) != NULL);
141  TEST_MSG("expected %i elements remaining in the lst", left - i);
142  TEST_MSG("failed extracting %i", i);
143  }
144 
145  TEST_CHECK((ret = fr_lst_num_elements(lst)) == 0);
146  TEST_MSG("%i elements remaining", ret);
147 
148  talloc_free(lst);
149  free(values);
150 }
151 
152 static void lst_test_skip_1(void)
153 {
154  lst_test(1);
155 }
156 
157 static void lst_test_skip_2(void)
158 {
159  lst_test(2);
160 }
161 
162 static void lst_test_skip_10(void)
163 {
164  lst_test(10);
165 }
166 
167 
168 static void lst_stress_realloc(void)
169 {
170  fr_lst_t *lst;
171  fr_heap_t *hp;
172  lst_thing *lst_array, *hp_array;
173  fr_fast_rand_t rand_ctx;
174  int ret;
175  lst_thing *from_lst, *from_hp;
176 
177  rand_ctx.a = fr_rand();
178  rand_ctx.b = fr_rand();
179 
180  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
181  TEST_CHECK(lst != NULL);
182  hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, 0);
183 
184  lst_array = calloc(2 * INITIAL_CAPACITY, sizeof(lst_thing));
185  hp_array = calloc(2 * INITIAL_CAPACITY, sizeof(lst_thing));
186 
187  /*
188  * Initialise random values
189  */
190  for (unsigned int i = 0; i < 2 * INITIAL_CAPACITY; i++) {
191  lst_array[i].data = hp_array[i].data = fr_fast_rand(&rand_ctx) % 65537;
192  }
193 
194  /* Add the first INITIAL_CAPACITY values to lst and to hp */
195  TEST_CASE("partial fill");
196  for (unsigned int i = 0; i < INITIAL_CAPACITY; i++) {
197  TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
198  TEST_MSG("lst insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
199  TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
200  TEST_MSG("heap insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
201  }
202 
203  /* Pop INITIAL_CAPACITY / 2 values from each (they should all be equal) */
204  TEST_CASE("partial pop");
205  for (unsigned int i = 0; i < INITIAL_CAPACITY / 2; i++) {
206  TEST_CHECK((from_lst = fr_lst_pop(lst)) != NULL);
207  TEST_CHECK((from_hp = fr_heap_pop(&hp)) != NULL);
208  TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
209  }
210 
211  /*
212  * Add the second INITIAL_CAPACITY values to lst and to hp.
213  * This should force lst to move entries to maintain adjacency,
214  * which is what we're testing here.
215  */
216  TEST_CASE("force move with expansion");
217  for (unsigned int i = INITIAL_CAPACITY; i < 2 * INITIAL_CAPACITY; i++) {
218  TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
219  TEST_MSG("lst insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
220  TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
221  TEST_MSG("heap insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
222  }
223 
224  /* pop the remaining 3 * INITIAL_CAPACITY / 2 values from each (they should all be equal) */
225  TEST_CASE("complete pop");
226  for (unsigned int i = 0; i < 3 * INITIAL_CAPACITY / 2; i++) {
227  TEST_CHECK((from_lst = fr_lst_pop(lst)) != NULL);
228  TEST_CHECK((from_hp = fr_heap_pop(&hp)) != NULL);
229  TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
230  }
231 
232  TEST_CHECK(fr_lst_num_elements(lst) == 0);
234 
235  talloc_free(lst);
236  talloc_free(hp);
237  free(lst_array);
238  free(hp_array);
239 }
240 
241 #define BURN_IN_OPS (10000000)
242 
243 static void lst_burn_in(void)
244 {
245  fr_lst_t *lst = NULL;
246  lst_thing *array = NULL;
247  fr_fast_rand_t rand_ctx;
248  int insert_count = 0;
249 
250  rand_ctx.a = fr_rand();
251  rand_ctx.b = fr_rand();
252 
253  array = calloc(BURN_IN_OPS, sizeof(lst_thing));
254  for (unsigned int i = 0; i < BURN_IN_OPS; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
255 
256  /* Make init small to exercise growing the pivot stack. */
257  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 32);
258 
259  for (unsigned int i = 0; i < BURN_IN_OPS; i++) {
260  lst_thing *ret_thing = NULL;
261  int ret_insert = -1;
262 
263  if (fr_lst_num_elements(lst) == 0) {
264  insert:
265  TEST_CHECK((ret_insert = fr_lst_insert(lst, &array[insert_count])) >= 0);
266  insert_count++;
267  } else {
268  switch (fr_fast_rand(&rand_ctx) % 3) {
269  case 0: /* insert */
270  goto insert;
271 
272  case 1: /* pop */
273  ret_thing = fr_lst_pop(lst);
274  TEST_CHECK(ret_thing != NULL);
275  break;
276  case 2: /* peek */
277  ret_thing = fr_lst_peek(lst);
278  TEST_CHECK(ret_thing != NULL);
279  break;
280  }
281  }
282  }
283 
284  talloc_free(lst);
285  free(array);
286 }
287 
288 #define LST_CYCLE_SIZE (1600000)
289 
290 static void lst_cycle(void)
291 {
292  fr_lst_t *lst;
293  int i;
294  lst_thing *values;
295  int to_remove;
296  int inserted, removed;
297  int ret;
298  fr_time_t start_insert, start_remove, start_swap, end;
299 
300  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
301  TEST_CHECK(lst != NULL);
302 
303  values = calloc(LST_CYCLE_SIZE, sizeof(lst_thing));
304 
305  /*
306  * Initialise random values
307  */
309 
310  start_insert = fr_time();
311  TEST_CASE("insertions");
312  for (i = 0; i < LST_CYCLE_SIZE; i++) {
313  TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
314  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
315  }
317 
318  TEST_CASE("pop");
319 
320  /*
321  * Remove a random number of elements from the LST
322  */
323  to_remove = fr_lst_num_elements(lst) / 2;
324  start_remove = fr_time();
325  for (i = 0; i < to_remove; i++) {
326  TEST_CHECK(fr_lst_pop(lst) != NULL);
327  TEST_MSG("failed extracting %i", i);
328  TEST_MSG("expected %i elements remaining in the LST", to_remove - i);
329  }
330 
331  /*
332  * Now swap the inserted and removed set creating churn
333  */
334  start_swap = fr_time();
335 
336  inserted = 0;
337  removed = 0;
338 
339  for (i = 0; i < LST_CYCLE_SIZE; i++) {
340  if (values[i].idx == 0) {
341  TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
342  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
343  inserted++;
344  } else {
345  TEST_CHECK((ret = fr_lst_extract(lst, &values[i])) >= 0);
346  TEST_MSG("element %i removal failed, returned %i", i, ret);
347  removed++;
348  }
349  }
350 
351  TEST_CHECK(removed == (LST_CYCLE_SIZE - to_remove));
352  TEST_MSG("expected %i", LST_CYCLE_SIZE - to_remove);
353  TEST_MSG("got %i", removed);
354 
355  TEST_CHECK(inserted == to_remove);
356  TEST_MSG("expected %i", to_remove);
357  TEST_MSG("got %i", inserted);
358 
359  end = fr_time();
360 
361  TEST_MSG_ALWAYS("\ncycle size: %d\n", LST_CYCLE_SIZE);
362  TEST_MSG_ALWAYS("insert: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(start_remove, start_insert)) / (double)NSEC);
363  TEST_MSG_ALWAYS("extract: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(start_swap, start_remove)) / (double)NSEC);
364  TEST_MSG_ALWAYS("swap: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(end, start_swap)) / (double)NSEC);
365 
366  talloc_free(lst);
367  free(values);
368 }
369 
370 static void lst_iter(void)
371 {
372  fr_lst_t *lst;
374  lst_thing values[NVALUES], *data;
375  unsigned int total;
376 
377  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
378  TEST_CHECK(lst != NULL);
379 
380  populate_values(values, NUM_ELEMENTS(values));
381 
382  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) TEST_CHECK(fr_lst_insert(lst, &values[i]) == 0);
383 
384  data = fr_lst_iter_init(lst, &iter);
385 
386  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++, data = fr_lst_iter_next(lst, &iter)) {
387  TEST_CHECK(data != NULL);
388  TEST_CHECK(!data->visited);
389  TEST_CHECK(data->idx > 0);
390  data->visited = true;
391  }
392 
393  TEST_CHECK(data == NULL);
394 
395  total = 0;
396  fr_lst_foreach(lst, lst_thing, item) {
397  total += item->data;
398  }}
399  TEST_CHECK(total = 190);
400 
402 }
403 
404 static CC_HINT(noinline) lst_thing *array_pop(lst_thing **array, unsigned int count)
405 {
406  lst_thing *low = NULL;
407  unsigned int idx = 0;
408 
409  for (unsigned int j = 0; j < count; j++) {
410  if (!array[j]) continue;
411 
412  if (!low || (lst_cmp(array[j], low) < 0)) {
413  idx = j;
414  low = array[j];
415  }
416  }
417  if (low) array[idx] = NULL;
418 
419  return low;
420 }
421 
422 /** Benchmarks for LSTs vs heaps when used as queues
423  *
424  */
425 static void queue_cmp(unsigned int count)
426 {
427  fr_lst_t *lst;
428  fr_heap_t *hp;
429 
430  lst_thing *values;
431 
432  unsigned int i;
433 
434  values = talloc_array(NULL, lst_thing, count);
435 
436  /*
437  * Check times for LST alloc, insert, pop
438  */
439  {
440  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
441 
442  populate_values(values, count);
443 
444  start_alloc = fr_time();
445  lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
446  end_alloc = fr_time();
447  TEST_CHECK(lst != NULL);
448 
449  start_insert = fr_time();
450  for (i = 0; i < count; i++) TEST_CHECK(fr_lst_insert(lst, &values[i]) == 0);
451  end_insert = fr_time();
452 
453  start_pop = fr_time();
454  for (i = 0; i < count; i++) {
455  TEST_CHECK(fr_lst_pop(lst) != NULL);
456  if (i == 0) end_pop_first = fr_time();
457 
458  TEST_MSG("expected %u elements remaining in the lst", count - i);
459  TEST_MSG("failed extracting %u", i);
460  }
461  end_pop = fr_time();
462 
463  TEST_MSG_ALWAYS("\nlst size: %u\n", count);
464  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
465  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
466  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
467  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
468 
469  talloc_free(lst);
470  }
471 
472  /*
473  * Check times for heap alloc, insert, pop
474  */
475  {
476  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
477 
478  populate_values(values, count);
479 
480  start_alloc = fr_time();
481  hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, count);
482  end_alloc = fr_time();
483  TEST_CHECK(hp != NULL);
484 
485  start_insert = fr_time();
486  for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
487  end_insert = fr_time();
488 
489  start_pop = fr_time();
490  for (i = 0; i < count; i++) {
491  TEST_CHECK(fr_heap_pop(&hp) != NULL);
492  if (i == 0) end_pop_first = fr_time();
493 
494  TEST_MSG("expected %u elements remaining in the heap", count - i);
495  TEST_MSG("failed extracting %u", i);
496  }
497  end_pop = fr_time();
498 
499  TEST_MSG_ALWAYS("\nheap size: %u\n", count);
500  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
501  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
502  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
503  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
504 
505  talloc_free(hp);
506  }
507 
508  /*
509  * Array
510  */
511  {
512  lst_thing **array;
513  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first;
514 
515  populate_values(values, count);
516  end_pop_first = fr_time_wrap(0);
517 
518  start_alloc = fr_time();
519  array = talloc_array(NULL, lst_thing *, count);
520  end_alloc = fr_time();
521 
522  start_insert = fr_time();
523  for (i = 0; i < count; i++) array[i] = &values[i];
524  end_insert = fr_time();
525 
526  start_pop = fr_time();
527  for (i = 0; i < count; i++) {
528  TEST_CHECK(array_pop(array, count) != NULL);
529  if (i == 0) end_pop_first = fr_time();
530  }
531  end_pop = fr_time();
532 
533  TEST_MSG_ALWAYS("\narray size: %u\n", count);
534  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
535  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
536  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
537  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
538 
540  }
541 
542  talloc_free(values);
543 }
544 
545 static void queue_cmp_10(void)
546 {
547  queue_cmp(10);
548 }
549 
550 static void queue_cmp_50(void)
551 {
552  queue_cmp(50);
553 }
554 
555 static void queue_cmp_100(void)
556 {
557  queue_cmp(100);
558 }
559 
560 static void queue_cmp_1000(void)
561 {
562  queue_cmp(1000);
563 }
564 
566  /*
567  * Basic tests
568  */
569  { "lst_test_basic", lst_test_basic },
570  { "lst_test_skip_1", lst_test_skip_1 },
571  { "lst_test_skip_2", lst_test_skip_2 },
572  { "lst_test_skip_10", lst_test_skip_10 },
573  { "lst_stress_realloc", lst_stress_realloc },
574  { "lst_burn_in", lst_burn_in },
575  { "lst_cycle", lst_cycle },
576  { "lst_iter", lst_iter },
577  { "queue_cmp_10", queue_cmp_10 },
578  { "queue_cmp_50", queue_cmp_50 },
579  { "queue_cmp_100", queue_cmp_100 },
580  { "queue_cmp_1000", queue_cmp_1000 },
581  { NULL }
582 };
#define TEST_MSG_ALWAYS(...)
Definition: acutest.h:222
#define TEST_CASE(name)
Definition: acutest.h:184
#define TEST_MSG(...)
Definition: acutest.h:215
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define NUM_ELEMENTS(_t)
Definition: build.h:335
fr_dcursor_iter_t iter
Definition: dcursor.h:147
return item
Definition: dcursor.h:553
Test enumeration values.
Definition: dict_test.h:92
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
Definition: heap.c:322
#define INITIAL_CAPACITY
Definition: heap.c:31
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition: heap.c:146
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition: heap.h:100
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
Definition: heap.h:179
The main heap structure.
Definition: heap.h:66
free(array)
Functions for a Leftmost Skeleton Tree.
int fr_lst_extract(fr_lst_t *lst, void *data)
Remove an element from an LST.
Definition: lst.c:715
void * fr_lst_pop(fr_lst_t *lst)
Definition: lst.c:695
void * fr_lst_iter_next(fr_lst_t *lst, fr_lst_iter_t *iter)
Get the next entry in an LST.
Definition: lst.c:785
fr_lst_index_t idx
Starting index, initially zero.
Definition: lst.c:62
int fr_lst_insert(fr_lst_t *lst, void *data)
Definition: lst.c:731
unsigned int fr_lst_num_elements(fr_lst_t *lst)
Definition: lst.c:750
void * fr_lst_peek(fr_lst_t *lst)
Definition: lst.c:701
void * fr_lst_iter_init(fr_lst_t *lst, fr_lst_iter_t *iter)
Iterate over entries in LST.
Definition: lst.c:766
Definition: lst.c:60
#define FR_LST_VERIFY(_lst)
Definition: lst.h:119
#define fr_lst_alloc(_ctx, _cmp, _type, _field, _init)
Creates an LST that can be used with non-talloced elements.
Definition: lst.h:65
static bool fr_lst_entry_inserted(fr_lst_index_t lst_id)
Check if an entry is inserted into an LST.
Definition: lst.h:97
fr_lst_index_t fr_lst_iter_t
Definition: lst.h:45
unsigned int fr_lst_index_t
Definition: lst.h:43
#define fr_lst_foreach(_lst, _type, _data)
Iterate over the contents of an LST.
Definition: lst.h:140
static void queue_cmp_100(void)
Definition: lst_tests.c:555
static void queue_cmp(unsigned int count)
Benchmarks for LSTs vs heaps when used as queues.
Definition: lst_tests.c:425
TEST_LIST
Definition: lst_tests.c:565
TEST_CHECK(total=190)
static void lst_test_skip_10(void)
Definition: lst_tests.c:162
#define NVALUES
Definition: lst_tests.c:64
static void lst_test(int skip)
Definition: lst_tests.c:93
unsigned int data
Definition: lst_tests.c:15
static int8_t lst_cmp(void const *one, void const *two)
Definition: lst_tests.c:33
#define LST_TEST_SIZE
Definition: lst_tests.c:91
#define BURN_IN_OPS
Definition: lst_tests.c:241
fr_lst_index_t idx
Definition: lst_tests.c:16
static void queue_cmp_50(void)
Definition: lst_tests.c:550
static void lst_cycle(void)
Definition: lst_tests.c:290
static void lst_burn_in(void)
Definition: lst_tests.c:243
static void lst_test_basic(void)
Definition: lst_tests.c:65
static void lst_iter(void)
Definition: lst_tests.c:370
#define LST_CYCLE_SIZE
Definition: lst_tests.c:288
static void queue_cmp_1000(void)
Definition: lst_tests.c:560
static void lst_test_skip_2(void)
Definition: lst_tests.c:157
static void queue_cmp_10(void)
Definition: lst_tests.c:545
static bool fr_lst_contains(fr_lst_t *lst, void *data)
Definition: lst_tests.c:24
static void lst_test_skip_1(void)
Definition: lst_tests.c:152
static void lst_stress_realloc(void)
Definition: lst_tests.c:168
static void populate_values(lst_thing values[], unsigned int len)
Definition: lst_tests.c:40
static lst_thing * array_pop(lst_thing **array, unsigned int count)
Definition: lst_tests.c:404
bool visited
Definition: lst_tests.c:17
talloc_free(lst)
static size_t array[MY_ARRAY_SIZE]
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
Definition: rand.c:280
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
uint32_t b
Definition: rand.h:55
uint32_t a
Definition: rand.h:55
Smaller fast random number generator.
Definition: rand.h:54
return count
Definition: module.c:163
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition: time.h:154
#define fr_time_wrap(_time)
Definition: time.h:145
#define NSEC
Definition: time.h:379
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition: time.h:229
"server local" time.
Definition: time.h:69
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
static fr_slen_t data
Definition: value.h:1265