The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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
23RCSID("$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
45typedef struct {
47 int foo;
48 int bar;
49} fr_test_t;
50
51static size_t used = 0;
52static size_t array[MY_ARRAY_SIZE];
55
56static int debug_lvl = 0;
57static bool touch_memory = false;
58
59static char const *seed_string = "foo";
60static size_t seed_string_len = 3;
61
62static size_t reserve_size = 2048;
63static size_t allocation_mask = 0x3ff;
64
65/**********************************************************************/
66typedef struct request_s request_t;
68void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request);
69
71{
72 return NULL;
73}
74
75void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
76{
77}
78
79/**********************************************************************/
80
81
82static void alloc_blocks(fr_message_set_t *ms, uint32_t *seed, UNUSED int *start, int *end)
83{
84 int i;
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
137static 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
178static 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
188int main(int argc, char *argv[])
189{
190 int c;
191 int i, start, end, ret;
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");
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:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define UNUSED
Definition build.h:315
#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
int fr_message_done(fr_message_t *m)
Mark a message as done.
Definition message.c:190
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
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_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition message.c:934
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
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
#define fr_assert(_expr)
Definition rad_assert.h:38
static TALLOC_CTX * autofree
Optional arguments for initialising requests.
Definition request.h:254
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
#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