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: 86a8e1f70a1ae6941222ce3ab0422098f22eaf17 $
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: 86a8e1f70a1ae6941222ce3ab0422098f22eaf17 $")
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
30#include <sys/time.h>
31
32#ifdef HAVE_GETOPT_H
33# include <getopt.h>
34#endif
35
36#define MPRINT1 if (debug_lvl) printf
37#define MPRINT2 if (debug_lvl > 1) printf
38
39#define ALLOC_SIZE (8)
40#define ARRAY_SIZE (4 * ALLOC_SIZE)
41#define MY_ARRAY_SIZE (16 * ARRAY_SIZE)
42
43typedef struct {
45 int foo;
46 int bar;
47} fr_test_t;
48
49static size_t used = 0;
50static size_t array[MY_ARRAY_SIZE];
53
54static int debug_lvl = 0;
55static bool touch_memory = false;
56
57static char const *seed_string = "foo";
58static size_t seed_string_len = 3;
59
60static size_t reserve_size = 2048;
61static size_t allocation_mask = 0x3ff;
62
63static void alloc_blocks(fr_message_set_t *ms, uint32_t *seed, UNUSED int *start, int *end)
64{
65 int i;
67
68 /*
69 * We can't allocated the entire array, and we can't
70 * over-fill the array.
71 */
73
74 MPRINT2("BLOCK ALLOC %d\n", my_alloc_size);
75
76 for (i = 0; i < my_alloc_size; i++) {
77 int index;
78 fr_message_t *m;
79
80 index = (*end + i) & (MY_ARRAY_SIZE - 1);
81
83 *seed = hash;
84
86 hash++; /* can't have it zero... */
87
88 array[index] = hash;
89
91 if (m == NULL) fr_exit_now(EXIT_FAILURE);
92
93 messages[index] = (fr_test_t *) fr_message_alloc(ms, m, hash);
94 if (messages[index] != (void *) m) fr_exit_now(EXIT_FAILURE);
95
96 if (touch_memory) {
97 size_t j;
98 size_t k = 0;
99
100 for (j = 0; j < m->data_size; j++) {
101 k += m->data[j];
102 }
103
104 m->data[0] = k;
105 }
106
107 if (debug_lvl > 1) printf("%08x\t", hash);
108
109 if (m->status != FR_MESSAGE_USED) fr_exit_now(EXIT_FAILURE);
110
111 used += hash;
112// fr_assert(fr_ring_buffer_used(rb) == used);
113 }
114
115 *end += my_alloc_size;
116}
117
118static void free_blocks(UNUSED fr_message_set_t *ms, UNUSED uint32_t *seed, int *start, int *end)
119{
120 int i;
121
123
124 MPRINT2("BLOCK FREE %d\n", my_alloc_size);
125
126 for (i = 0; i < my_alloc_size; i++) {
127 int index;
128 int ret;
129 fr_message_t *m;
130
131 index = (*start + i) & (MY_ARRAY_SIZE - 1);
132
133 m = &messages[index]->m;
134
135 if(m->status != FR_MESSAGE_USED) fr_exit_now(EXIT_FAILURE);
136
137 ret = fr_message_done(m);
138
139 if (ret != 0) fr_exit_now(EXIT_FAILURE);
140
141 used -= array[index];
142
143 array[index] = 0;
144 messages[index] = NULL;
145 }
146
147 *start += my_alloc_size;
148 if (*start >= MY_ARRAY_SIZE) {
149 *start -= MY_ARRAY_SIZE;
150 *end -= MY_ARRAY_SIZE;
151 fr_assert(*start <= *end);
152 fr_assert(*start < MY_ARRAY_SIZE);
153 }
154}
155
156static NEVER_RETURNS void usage(void)
157{
158 fprintf(stderr, "usage: message_set_test [OPTS]\n");
159 fprintf(stderr, " -s <string> Set random seed to <string>.\n");
160 fprintf(stderr, " -t Touch 'packet' memory.\n");
161 fprintf(stderr, " -x Debugging mode.\n");
162
163 fr_exit_now(EXIT_SUCCESS);
164}
165
166int main(int argc, char *argv[])
167{
168 int c;
169 int i, start, end, ret;
170 fr_message_set_t *ms, *ms2;
171 uint32_t seed;
172
173 TALLOC_CTX *autofree = talloc_autofree_context();
174
175 memset(array, 0, sizeof(array));
176 memset(messages, 0, sizeof(messages));
177
178 while ((c = getopt(argc, argv, "hs:tx")) != -1) switch (c) {
179 case 's':
180 seed_string = optarg;
181 seed_string_len = strlen(optarg);
182 break;
183
184 case 't':
185 touch_memory = true;
186 break;
187
188 case 'x':
189 debug_lvl++;
190 break;
191
192 case 'h':
193 default:
194 usage();
195 }
196#if 0
197 argc -= (optind - 1);
198 argv += (optind - 1);
199#endif
200
201 ms = fr_message_set_create(autofree, ARRAY_SIZE, sizeof(fr_message_t), ARRAY_SIZE * 1024, false);
202 if (!ms) {
203 fprintf(stderr, "Failed creating message set\n");
204 fr_exit_now(EXIT_FAILURE);
205 }
206
207 seed = 0xabcdef;
208 start = 0;
209 end = 0;
211
212 /*
213 * Allocate the first set of blocks.
214 */
215 alloc_blocks(ms, &seed, &start, &end);
216
217 /*
218 * Do 1000 rounds of alloc / free.
219 */
220 for (i = 0; i < 4; i++) {
221 MPRINT2("Loop %d (used %zu) \n", i, used);
222 alloc_blocks(ms, &seed, &start, &end);
223
224 free_blocks(ms, &seed, &start, &end);
225 }
226
227 MPRINT1("TEST 1 used %d (%zu)\n", fr_message_set_messages_used(ms), used);
228
229 if (debug_lvl) fr_message_set_debug(stdout, ms);
230
231 /*
232 * Double the size of the allocations
233 */
234 reserve_size <<= 1;
235
236 allocation_mask <<= 1;
237 allocation_mask |= 1;
238
239 /*
240 * Do another 1000 rounds of alloc / free.
241 */
242 for (i = 0; i < 1000; i++) {
243 MPRINT2("Second 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 2 used %d\n", fr_message_set_messages_used(ms));
250
251 if (debug_lvl) fr_message_set_debug(stdout, ms);
252 /*
253 * Double the size of the allocations
254 */
255 reserve_size <<= 1;
256
257 allocation_mask <<= 1;
258 allocation_mask |= 1;
259
260 /*
261 * Do another 1000 rounds of alloc / free.
262 */
263 for (i = 0; i < 1000; i++) {
264 MPRINT2("Third loop %d (used %zu) \n", i, used);
265 alloc_blocks(ms, &seed, &start, &end);
266
267 free_blocks(ms, &seed, &start, &end);
268 }
269
270 /*
271 * Double the number of the allocations,
272 * but decrease the allocation size back to 1K
273 */
274 my_alloc_size *= 2;
275 reserve_size = 2048;
276 allocation_mask = (reserve_size - 1) >> 1;
277
278 MPRINT1("TEST 3 used %d\n", fr_message_set_messages_used(ms));
279
280 if (debug_lvl) fr_message_set_debug(stdout, ms);
281
282 /*
283 * Do another 1000 rounds of alloc / free.
284 */
285 for (i = 0; i < 1000; i++) {
286 MPRINT2("Fourth 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 MPRINT1("TEST 4 used %d\n", fr_message_set_messages_used(ms));
293
294 if (debug_lvl) fr_message_set_debug(stdout, ms);
295
296#if 0
297
298 /*
299 * Double the number of the allocations again,
300 * leaving the allocation size alone.
301 */
302 my_alloc_size *= 2;
303
304 /*
305 * Do another 10000 rounds of alloc / free.
306 */
307 for (i = 0; i < 10000; i++) {
308 MPRINT2("fifth 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 5 used %d\n", fr_message_set_messages_used(ms));
315
316 if (debug_lvl) fr_message_set_debug(stdout, ms);
317
318 /*
319 * Double the number of the allocations again,
320 * leaving the allocation size alone.
321 */
322 my_alloc_size *= 2;
323
324 /*
325 * Do another 10000 rounds of alloc / free.
326 */
327 for (i = 0; i < 10000; i++) {
328 MPRINT2("sixth loop %d (used %zu) \n", i, used);
329 alloc_blocks(ms, &seed, &start, &end);
330
331 free_blocks(ms, &seed, &start, &end);
332 }
333
334 MPRINT1("TEST 6 used %d\n", fr_message_set_messages_used(ms));
335
336 if (debug_lvl) fr_message_set_debug(stdout, ms);
337#endif
338
339 my_alloc_size = end - start;
340 free_blocks(ms, &seed, &start, &end);
341
342 if (used != 0) fr_exit_now(EXIT_FAILURE);
343
344 for (i = 0; i < MY_ARRAY_SIZE; i++) {
345 if (messages[i] != NULL) fr_exit_now(EXIT_FAILURE);
346 }
347
348 if (debug_lvl) {
349 fr_time_t start_t, end_t;
350
351 start_t = fr_time();
352
353 /*
354 * Do another 10000 rounds of alloc / free.
355 */
356 my_alloc_size = 100;
357
358 for (i = 0; i < 10000; i++) {
359 alloc_blocks(ms, &seed, &start, &end);
360
361 free_blocks(ms, &seed, &start, &end);
362 }
363
364 end_t = fr_time();
365
366 printf("\nELAPSED %"PRIu64".%06d seconds, %d allocation / free cycles\n\n",
367 fr_time_delta_to_sec(fr_time_sub(end_t, start_t)),
368 (int) fr_time_delta_to_usec(fr_time_sub(end_t, start_t)),
369 my_alloc_size * 10000);
370 }
371
372 /*
373 * Force all messages to be garbage collected
374 */
375 MPRINT1("GC\n");
377
378 if (debug_lvl) fr_message_set_debug(stdout, ms);
379
380 /*
381 * After the garbage collection, all messages marked "done" MUST also be marked "free".
382 */
384 fr_assert(ret == 0);
385
386 /*
387 * Allocate a message set with small initial ring buffer size, but allowing for "unlimited" size.
388 */
390 if (!ms2) {
391 fprintf(stderr, "Failed creating message set\n");
392 fr_exit_now(EXIT_FAILURE);
393 }
394
395 /*
396 * Use the new message set - the allocations will be beyond the origial ring buffer size.
397 */
398 alloc_blocks(ms2, &seed, &start, &end);
399 free_blocks(ms2, &seed, &start, &end);
401
402 return ret;
403}
404
static TALLOC_CTX * autofree
Definition fuzzer.c:44
#define RCSID(id)
Definition build.h:506
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:334
#define UNUSED
Definition build.h:336
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:236
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:881
#define fr_time()
Definition event.c:60
unsigned int uint32_t
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size, bool unlimited_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:195
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:1000
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
Definition message.c:1224
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
Definition message.c:1250
void fr_message_set_debug(FILE *fp, fr_message_set_t *ms)
Print debug information about the message set.
Definition message.c:1274
fr_message_t * fr_message_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition message.c:946
A Message set, composed of message headers and ring buffer data.
Definition message.c:94
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]
#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)
static int debug_lvl
#define fr_assert(_expr)
Definition rad_assert.h:37
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:48
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
Definition time.h:647
static int64_t fr_time_delta_to_usec(fr_time_delta_t delta)
Definition time.h:632
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69