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: b1413f1d4c717dec20fe854e8ce9089785184800 $
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: b1413f1d4c717dec20fe854e8ce9089785184800 $")
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
65static void alloc_blocks(fr_message_set_t *ms, uint32_t *seed, UNUSED int *start, int *end)
66{
67 int i;
69
70 /*
71 * We can't allocated the entire array, and we can't
72 * over-fill the array.
73 */
75
76 MPRINT2("BLOCK ALLOC %d\n", my_alloc_size);
77
78 for (i = 0; i < my_alloc_size; i++) {
79 int index;
80 fr_message_t *m;
81
82 index = (*end + i) & (MY_ARRAY_SIZE - 1);
83
85 *seed = hash;
86
88 hash++; /* can't have it zero... */
89
90 array[index] = hash;
91
93 if (m == NULL) fr_exit_now(EXIT_FAILURE);
94
95 messages[index] = (fr_test_t *) fr_message_alloc(ms, m, hash);
96 if (messages[index] != (void *) m) fr_exit_now(EXIT_FAILURE);
97
98 if (touch_memory) {
99 size_t j;
100 size_t k = 0;
101
102 for (j = 0; j < m->data_size; j++) {
103 k += m->data[j];
104 }
105
106 m->data[0] = k;
107 }
108
109 if (debug_lvl > 1) printf("%08x\t", hash);
110
111 if (m->status != FR_MESSAGE_USED) fr_exit_now(EXIT_FAILURE);
112
113 used += hash;
114// fr_assert(fr_ring_buffer_used(rb) == used);
115 }
116
117 *end += my_alloc_size;
118}
119
120static void free_blocks(UNUSED fr_message_set_t *ms, UNUSED uint32_t *seed, int *start, int *end)
121{
122 int i;
123
125
126 MPRINT2("BLOCK FREE %d\n", my_alloc_size);
127
128 for (i = 0; i < my_alloc_size; i++) {
129 int index;
130 int ret;
131 fr_message_t *m;
132
133 index = (*start + i) & (MY_ARRAY_SIZE - 1);
134
135 m = &messages[index]->m;
136
137 if(m->status != FR_MESSAGE_USED) fr_exit_now(EXIT_FAILURE);
138
139 ret = fr_message_done(m);
140
141 if (ret != 0) fr_exit_now(EXIT_FAILURE);
142
143 used -= array[index];
144
145 array[index] = 0;
146 messages[index] = NULL;
147 }
148
149 *start += my_alloc_size;
150 if (*start > MY_ARRAY_SIZE) {
151 *start -= MY_ARRAY_SIZE;
152 *end -= MY_ARRAY_SIZE;
153 fr_assert(*start <= *end);
154 fr_assert(*start < MY_ARRAY_SIZE);
155 }
156}
157
158static NEVER_RETURNS void usage(void)
159{
160 fprintf(stderr, "usage: message_set_test [OPTS]\n");
161 fprintf(stderr, " -s <string> Set random seed to <string>.\n");
162 fprintf(stderr, " -t Touch 'packet' memory.\n");
163 fprintf(stderr, " -x Debugging mode.\n");
164
165 fr_exit_now(EXIT_SUCCESS);
166}
167
168int main(int argc, char *argv[])
169{
170 int c;
171 int i, start, end, ret;
172 fr_message_set_t *ms, *ms2;
173 uint32_t seed;
174
175 TALLOC_CTX *autofree = talloc_autofree_context();
176
177 memset(array, 0, sizeof(array));
178 memset(messages, 0, sizeof(messages));
179
180 while ((c = getopt(argc, argv, "hs:tx")) != -1) switch (c) {
181 case 's':
182 seed_string = optarg;
183 seed_string_len = strlen(optarg);
184 break;
185
186 case 't':
187 touch_memory = true;
188 break;
189
190 case 'x':
191 debug_lvl++;
192 break;
193
194 case 'h':
195 default:
196 usage();
197 }
198#if 0
199 argc -= (optind - 1);
200 argv += (optind - 1);
201#endif
202
203 ms = fr_message_set_create(autofree, ARRAY_SIZE, sizeof(fr_message_t), ARRAY_SIZE * 1024, false);
204 if (!ms) {
205 fprintf(stderr, "Failed creating message set\n");
206 fr_exit_now(EXIT_FAILURE);
207 }
208
209 seed = 0xabcdef;
210 start = 0;
211 end = 0;
213
214 /*
215 * Allocate the first set of blocks.
216 */
217 alloc_blocks(ms, &seed, &start, &end);
218
219 /*
220 * Do 1000 rounds of alloc / free.
221 */
222 for (i = 0; i < 4; i++) {
223 MPRINT2("Loop %d (used %zu) \n", i, used);
224 alloc_blocks(ms, &seed, &start, &end);
225
226 free_blocks(ms, &seed, &start, &end);
227 }
228
229 MPRINT1("TEST 1 used %d (%zu)\n", fr_message_set_messages_used(ms), used);
230
231 if (debug_lvl) fr_message_set_debug(stdout, ms);
232
233 /*
234 * Double the size of the allocations
235 */
236 reserve_size <<= 1;
237
238 allocation_mask <<= 1;
239 allocation_mask |= 1;
240
241 /*
242 * Do another 1000 rounds of alloc / free.
243 */
244 for (i = 0; i < 1000; i++) {
245 MPRINT2("Second loop %d (used %zu) \n", i, used);
246 alloc_blocks(ms, &seed, &start, &end);
247
248 free_blocks(ms, &seed, &start, &end);
249 }
250
251 MPRINT1("TEST 2 used %d\n", fr_message_set_messages_used(ms));
252
253 if (debug_lvl) fr_message_set_debug(stdout, ms);
254 /*
255 * Double the size of the allocations
256 */
257 reserve_size <<= 1;
258
259 allocation_mask <<= 1;
260 allocation_mask |= 1;
261
262 /*
263 * Do another 1000 rounds of alloc / free.
264 */
265 for (i = 0; i < 1000; i++) {
266 MPRINT2("Third loop %d (used %zu) \n", i, used);
267 alloc_blocks(ms, &seed, &start, &end);
268
269 free_blocks(ms, &seed, &start, &end);
270 }
271
272 /*
273 * Double the number of the allocations,
274 * but decrease the allocation size back to 1K
275 */
276 my_alloc_size *= 2;
277 reserve_size = 2048;
278 allocation_mask = (reserve_size - 1) >> 1;
279
280 MPRINT1("TEST 3 used %d\n", fr_message_set_messages_used(ms));
281
282 if (debug_lvl) fr_message_set_debug(stdout, ms);
283
284 /*
285 * Do another 1000 rounds of alloc / free.
286 */
287 for (i = 0; i < 1000; i++) {
288 MPRINT2("Fourth loop %d (used %zu) \n", i, used);
289 alloc_blocks(ms, &seed, &start, &end);
290
291 free_blocks(ms, &seed, &start, &end);
292 }
293
294 MPRINT1("TEST 4 used %d\n", fr_message_set_messages_used(ms));
295
296 if (debug_lvl) fr_message_set_debug(stdout, ms);
297
298#if 0
299
300 /*
301 * Double the number of the allocations again,
302 * leaving the allocation size alone.
303 */
304 my_alloc_size *= 2;
305
306 /*
307 * Do another 10000 rounds of alloc / free.
308 */
309 for (i = 0; i < 10000; i++) {
310 MPRINT2("fifth loop %d (used %zu) \n", i, used);
311 alloc_blocks(ms, &seed, &start, &end);
312
313 free_blocks(ms, &seed, &start, &end);
314 }
315
316 MPRINT1("TEST 5 used %d\n", fr_message_set_messages_used(ms));
317
318 if (debug_lvl) fr_message_set_debug(stdout, ms);
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("sixth 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 6 used %d\n", fr_message_set_messages_used(ms));
337
338 if (debug_lvl) fr_message_set_debug(stdout, ms);
339#endif
340
341 my_alloc_size = end - start;
342 free_blocks(ms, &seed, &start, &end);
343
344 if (used != 0) fr_exit_now(EXIT_FAILURE);
345
346 for (i = 0; i < MY_ARRAY_SIZE; i++) {
347 if (messages[i] != NULL) fr_exit_now(EXIT_FAILURE);
348 }
349
350 if (debug_lvl) {
351 fr_time_t start_t, end_t;
352
353 start_t = fr_time();
354
355 /*
356 * Do another 10000 rounds of alloc / free.
357 */
358 my_alloc_size = 100;
359
360 for (i = 0; i < 10000; i++) {
361 alloc_blocks(ms, &seed, &start, &end);
362
363 free_blocks(ms, &seed, &start, &end);
364 }
365
366 end_t = fr_time();
367
368 printf("\nELAPSED %"PRIu64".%06d seconds, %d allocation / free cycles\n\n",
369 fr_time_delta_to_sec(fr_time_sub(end_t, start_t)),
370 (int) fr_time_delta_to_usec(fr_time_sub(end_t, start_t)),
371 my_alloc_size * 10000);
372 }
373
374 /*
375 * Force all messages to be garbage collected
376 */
377 MPRINT1("GC\n");
379
380 if (debug_lvl) fr_message_set_debug(stdout, ms);
381
382 /*
383 * After the garbage collection, all messages marked "done" MUST also be marked "free".
384 */
386 fr_assert(ret == 0);
387
388 /*
389 * Allocate a message set with small initial ring buffer size, but allowing for "unlimited" size.
390 */
392 if (!ms2) {
393 fprintf(stderr, "Failed creating message set\n");
394 fr_exit_now(EXIT_FAILURE);
395 }
396
397 /*
398 * Use the new message set - the allocations will be beyond the origial ring buffer size.
399 */
400 alloc_blocks(ms2, &seed, &start, &end);
401 free_blocks(ms2, &seed, &start, &end);
403
404 return ret;
405}
406
static TALLOC_CTX * autofree
Definition fuzzer.c:46
#define RCSID(id)
Definition build.h:487
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:315
#define UNUSED
Definition build.h:317
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:226
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:850
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:128
int fr_message_done(fr_message_t *m)
Mark a message as done.
Definition message.c:196
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:1001
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
Definition message.c:1225
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
Definition message.c:1251
void fr_message_set_debug(FILE *fp, fr_message_set_t *ms)
Print debug information about the message set.
Definition message.c:1275
fr_message_t * fr_message_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition message.c:947
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]
#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:38
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
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