The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
message_set_test.c
Go to the documentation of this file.
1 /*
2  * message_set_test.c Tests for message sets
3  *
4  * Version: $Id: ad2272f781d674ebb18581b236d1048e7b4fd85d $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * @copyright 2016 Alan DeKok (aland@freeradius.org)
21  */
22 
23 RCSID("$Id: ad2272f781d674ebb18581b236d1048e7b4fd85d $")
24 
25 #include <freeradius-devel/io/message.h>
26 #include <freeradius-devel/util/debug.h>
27 #include <freeradius-devel/util/hash.h>
28 #include <freeradius-devel/util/syserror.h>
29 #include <freeradius-devel/util/talloc.h>
30 
31 #include <string.h>
32 #include <sys/time.h>
33 
34 #ifdef HAVE_GETOPT_H
35 # include <getopt.h>
36 #endif
37 
38 #define MPRINT1 if (debug_lvl) printf
39 #define MPRINT2 if (debug_lvl > 1) printf
40 
41 #define ALLOC_SIZE (8)
42 #define ARRAY_SIZE (4 * ALLOC_SIZE)
43 #define MY_ARRAY_SIZE (16 * ARRAY_SIZE)
44 
45 typedef struct {
47  int foo;
48  int bar;
49 } fr_test_t;
50 
51 static size_t used = 0;
52 static size_t array[MY_ARRAY_SIZE];
55 
56 static int debug_lvl = 0;
57 static bool touch_memory = false;
58 
59 static char const *seed_string = "foo";
60 static size_t seed_string_len = 3;
61 
62 static size_t reserve_size = 2048;
63 static size_t allocation_mask = 0x3ff;
64 
65 /**********************************************************************/
66 typedef struct request_s request_t;
68 void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request);
69 
71 {
72  return NULL;
73 }
74 
75 void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
76 {
77 }
78 
79 /**********************************************************************/
80 
81 
82 static void alloc_blocks(fr_message_set_t *ms, uint32_t *seed, UNUSED int *start, int *end)
83 {
84  int i;
85  uint32_t hash;
86 
87  /*
88  * We can't allocated the entire array, and we can't
89  * over-fill the array.
90  */
92 
93  MPRINT2("BLOCK ALLOC %d\n", my_alloc_size);
94 
95  for (i = 0; i < my_alloc_size; i++) {
96  int index;
97  fr_message_t *m;
98 
99  index = (*end + i) & (MY_ARRAY_SIZE - 1);
100 
102  *seed = hash;
103 
105  hash++; /* can't have it zero... */
106 
107  array[index] = hash;
108 
110  fr_assert(m != NULL);
111 
112  messages[index] = (fr_test_t *) fr_message_alloc(ms, m, hash);
113  fr_assert(messages[index] == (void *) m);
114 
115  if (touch_memory) {
116  size_t j;
117  size_t k = 0;
118 
119  for (j = 0; j < m->data_size; j++) {
120  k += m->data[j];
121  }
122 
123  m->data[0] = k;
124  }
125 
126  if (debug_lvl > 1) printf("%08x\t", hash);
127 
129 
130  used += hash;
131 // fr_assert(fr_ring_buffer_used(rb) == used);
132  }
133 
134  *end += my_alloc_size;
135 }
136 
137 static void free_blocks(UNUSED fr_message_set_t *ms, UNUSED uint32_t *seed, int *start, int *end)
138 {
139  int i;
140 
142 
143  MPRINT2("BLOCK FREE %d\n", my_alloc_size);
144 
145  for (i = 0; i < my_alloc_size; i++) {
146  int index;
147  int ret;
148  fr_message_t *m;
149 
150  index = (*start + i) & (MY_ARRAY_SIZE - 1);
151 
152  m = &messages[index]->m;
153 
155 
156  ret = fr_message_done(m);
157 #ifndef NDEBUG
158  fr_assert(ret == 0);
159 #else
160  if (ret != 0) fr_exit_now(EXIT_FAILURE);
161 #endif
162 
163  used -= array[index];
164 
165  array[index] = 0;
166  messages[index] = NULL;
167  }
168 
169  *start += my_alloc_size;
170  if (*start > MY_ARRAY_SIZE) {
171  *start -= MY_ARRAY_SIZE;
172  *end -= MY_ARRAY_SIZE;
173  fr_assert(*start <= *end);
174  fr_assert(*start < MY_ARRAY_SIZE);
175  }
176 }
177 
178 static NEVER_RETURNS void usage(void)
179 {
180  fprintf(stderr, "usage: message_set_test [OPTS]\n");
181  fprintf(stderr, " -s <string> Set random seed to <string>.\n");
182  fprintf(stderr, " -t Touch 'packet' memory.\n");
183  fprintf(stderr, " -x Debugging mode.\n");
184 
185  fr_exit_now(EXIT_SUCCESS);
186 }
187 
188 int main(int argc, char *argv[])
189 {
190  int c;
191  int i, start, end, ret;
192  fr_message_set_t *ms;
193  uint32_t seed;
194 
195  TALLOC_CTX *autofree = talloc_autofree_context();
196 
197  memset(array, 0, sizeof(array));
198  memset(messages, 0, sizeof(messages));
199 
200  while ((c = getopt(argc, argv, "hs:tx")) != -1) switch (c) {
201  case 's':
202  seed_string = optarg;
203  seed_string_len = strlen(optarg);
204  break;
205 
206  case 't':
207  touch_memory = true;
208  break;
209 
210  case 'x':
211  debug_lvl++;
212  break;
213 
214  case 'h':
215  default:
216  usage();
217  }
218 #if 0
219  argc -= (optind - 1);
220  argv += (optind - 1);
221 #endif
222 
224  if (!ms) {
225  fprintf(stderr, "Failed creating message set\n");
226  fr_exit_now(EXIT_FAILURE);
227  }
228 
229  seed = 0xabcdef;
230  start = 0;
231  end = 0;
233 
234  /*
235  * Allocate the first set of blocks.
236  */
237  alloc_blocks(ms, &seed, &start, &end);
238 
239  /*
240  * Do 1000 rounds of alloc / free.
241  */
242  for (i = 0; i < 4; i++) {
243  MPRINT2("Loop %d (used %zu) \n", i, used);
244  alloc_blocks(ms, &seed, &start, &end);
245 
246  free_blocks(ms, &seed, &start, &end);
247  }
248 
249  MPRINT1("TEST 1 used %d (%zu)\n", fr_message_set_messages_used(ms), used);
250 
251  if (debug_lvl) fr_message_set_debug(ms, stdout);
252 
253  /*
254  * Double the size of the allocations
255  */
256  reserve_size <<= 1;
257 
258  allocation_mask <<= 1;
259  allocation_mask |= 1;
260 
261  /*
262  * Do another 1000 rounds of alloc / free.
263  */
264  for (i = 0; i < 1000; i++) {
265  MPRINT2("Second loop %d (used %zu) \n", i, used);
266  alloc_blocks(ms, &seed, &start, &end);
267 
268  free_blocks(ms, &seed, &start, &end);
269  }
270 
271  MPRINT1("TEST 2 used %d\n", fr_message_set_messages_used(ms));
272 
273  if (debug_lvl) fr_message_set_debug(ms, stdout);
274  /*
275  * Double the size of the allocations
276  */
277  reserve_size <<= 1;
278 
279  allocation_mask <<= 1;
280  allocation_mask |= 1;
281 
282  /*
283  * Do another 1000 rounds of alloc / free.
284  */
285  for (i = 0; i < 1000; i++) {
286  MPRINT2("Third loop %d (used %zu) \n", i, used);
287  alloc_blocks(ms, &seed, &start, &end);
288 
289  free_blocks(ms, &seed, &start, &end);
290  }
291 
292  /*
293  * Double the number of the allocations,
294  * but decrease the allocation size back to 1K
295  */
296  my_alloc_size *= 2;
297  reserve_size = 2048;
298  allocation_mask = (reserve_size - 1) >> 1;
299 
300  MPRINT1("TEST 3 used %d\n", fr_message_set_messages_used(ms));
301 
302  if (debug_lvl) fr_message_set_debug(ms, stdout);
303 
304  /*
305  * Do another 1000 rounds of alloc / free.
306  */
307  for (i = 0; i < 1000; i++) {
308  MPRINT2("Fourth loop %d (used %zu) \n", i, used);
309  alloc_blocks(ms, &seed, &start, &end);
310 
311  free_blocks(ms, &seed, &start, &end);
312  }
313 
314  MPRINT1("TEST 4 used %d\n", fr_message_set_messages_used(ms));
315 
316  if (debug_lvl) fr_message_set_debug(ms, stdout);
317 
318 #if 0
319 
320  /*
321  * Double the number of the allocations again,
322  * leaving the allocation size alone.
323  */
324  my_alloc_size *= 2;
325 
326  /*
327  * Do another 10000 rounds of alloc / free.
328  */
329  for (i = 0; i < 10000; i++) {
330  MPRINT2("fifth loop %d (used %zu) \n", i, used);
331  alloc_blocks(ms, &seed, &start, &end);
332 
333  free_blocks(ms, &seed, &start, &end);
334  }
335 
336  MPRINT1("TEST 5 used %d\n", fr_message_set_messages_used(ms));
337 
338  if (debug_lvl) fr_message_set_debug(ms, stdout);
339 
340  /*
341  * Double the number of the allocations again,
342  * leaving the allocation size alone.
343  */
344  my_alloc_size *= 2;
345 
346  /*
347  * Do another 10000 rounds of alloc / free.
348  */
349  for (i = 0; i < 10000; i++) {
350  MPRINT2("sixth loop %d (used %zu) \n", i, used);
351  alloc_blocks(ms, &seed, &start, &end);
352 
353  free_blocks(ms, &seed, &start, &end);
354  }
355 
356  MPRINT1("TEST 6 used %d\n", fr_message_set_messages_used(ms));
357 
358  if (debug_lvl) fr_message_set_debug(ms, stdout);
359 #endif
360 
361  my_alloc_size = end - start;
362  free_blocks(ms, &seed, &start, &end);
363 
364  fr_assert(used == 0);
365 
366  for (i = 0; i < MY_ARRAY_SIZE; i++) {
367  fr_assert(messages[i] == NULL);
368  }
369 
370  if (debug_lvl) {
371  fr_time_t start_t, end_t;
372 
373  start_t = fr_time();
374 
375  /*
376  * Do another 10000 rounds of alloc / free.
377  */
378  my_alloc_size = 100;
379 
380  for (i = 0; i < 10000; i++) {
381  alloc_blocks(ms, &seed, &start, &end);
382 
383  free_blocks(ms, &seed, &start, &end);
384  }
385 
386  end_t = fr_time();
387 
388  printf("\nELAPSED %d.%06d seconds, %d allocation / free cycles\n\n",
389  (int) (end_t - start_t) / NSEC, (int) ((end_t - start_t) % NSEC),
390  my_alloc_size * 10000);
391  }
392 
393  /*
394  * Force all messages to be garbage collected
395  */
396  MPRINT1("GC\n");
397  fr_message_set_gc(ms);
398 
399  if (debug_lvl) fr_message_set_debug(ms, stdout);
400 
401  /*
402  * After the garbage collection, all messages marked "done" MUST also be marked "free".
403  */
405  fr_assert(ret == 0);
406 
407  return ret;
408 }
409 
int const char * file
Definition: acutest.h:702
va_list args
Definition: acutest.h:770
int const char int line
Definition: acutest.h:702
#define RCSID(id)
Definition: build.h:481
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
#define UNUSED
Definition: build.h:313
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:234
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition: hash.c:846
unsigned int uint32_t
Definition: merged_model.c:33
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size)
Create a message set.
Definition: message.c:127
int fr_message_done(fr_message_t *m)
Mark a message as done.
Definition: message.c:190
fr_message_t * fr_message_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition: message.c:934
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
Definition: message.c:1212
void fr_message_set_debug(fr_message_set_t *ms, FILE *fp)
Print debug information about the message set.
Definition: message.c:1262
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
Definition: message.c:1238
fr_message_t * fr_message_alloc(fr_message_set_t *ms, fr_message_t *m, size_t actual_packet_size)
Allocate packet data for a message.
Definition: message.c:988
A Message set, composed of message headers and ring buffer data.
Definition: message.c:95
uint8_t * data
pointer to the data in the ring buffer
Definition: message.h:49
size_t data_size
size of the data in the ring buffer
Definition: message.h:50
@ FR_MESSAGE_USED
Definition: message.h:39
fr_message_status_t status
free, used, done, etc.
Definition: message.h:45
static fr_test_t * messages[MY_ARRAY_SIZE]
int main(int argc, char *argv[])
static size_t reserve_size
static bool touch_memory
static size_t allocation_mask
static size_t array[MY_ARRAY_SIZE]
request_t * request_alloc(UNUSED TALLOC_CTX *ctx, UNUSED request_init_args_t const *args)
#define ARRAY_SIZE
#define MPRINT2
static size_t seed_string_len
#define MY_ARRAY_SIZE
#define MPRINT1
fr_message_t m
static char const * seed_string
static size_t used
static void free_blocks(UNUSED fr_message_set_t *ms, UNUSED uint32_t *seed, int *start, int *end)
static NEVER_RETURNS void usage(void)
static int my_alloc_size
#define ALLOC_SIZE
static void alloc_blocks(fr_message_set_t *ms, uint32_t *seed, UNUSED int *start, int *end)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
static int debug_lvl
static TALLOC_CTX * autofree
Definition: radclient-ng.c:107
Optional arguments for initialising requests.
Definition: request.h:254
static unsigned int hash(char const *username, unsigned int tablesize)
Definition: rlm_passwd.c:132
fr_assert(0)
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition: talloc.h:51
#define NSEC
Definition: time.h:379
"server local" time.
Definition: time.h:69