1 |
2 |
drasko |
/*
|
2 |
|
|
* Generic random allocation/deallocation test
|
3 |
|
|
*
|
4 |
|
|
* Copyright 2007 (C) Bahadir Balban
|
5 |
|
|
*
|
6 |
|
|
*/
|
7 |
|
|
#include <l4/macros.h>
|
8 |
|
|
#include <l4/config.h>
|
9 |
|
|
#include <l4/types.h>
|
10 |
|
|
#include INC_GLUE(memory.h)
|
11 |
|
|
|
12 |
|
|
#include <l4/lib/list.h>
|
13 |
|
|
#include <stdlib.h>
|
14 |
|
|
#include <stdio.h>
|
15 |
|
|
#include <time.h>
|
16 |
|
|
#include <string.h>
|
17 |
|
|
#include "test_alloc_generic.h"
|
18 |
|
|
#include "debug.h"
|
19 |
|
|
|
20 |
|
|
void print_test_state(unsigned int title,
|
21 |
|
|
print_alloc_state_t print_allocator_state)
|
22 |
|
|
{
|
23 |
|
|
switch (title) {
|
24 |
|
|
case TEST_STATE_BEGIN:
|
25 |
|
|
printf("=================\n"
|
26 |
|
|
"===== BEGIN =====\n"
|
27 |
|
|
"=================\n\n");
|
28 |
|
|
break;
|
29 |
|
|
case TEST_STATE_MIDDLE:
|
30 |
|
|
printf("==================\n"
|
31 |
|
|
"===== MIDDLE =====\n"
|
32 |
|
|
"==================\n\n");
|
33 |
|
|
break;
|
34 |
|
|
case TEST_STATE_END:
|
35 |
|
|
printf("===========\n"
|
36 |
|
|
"=== END ===\n"
|
37 |
|
|
"===========\n\n");
|
38 |
|
|
break;
|
39 |
|
|
case TEST_STATE_ERROR:
|
40 |
|
|
printf("=================\n"
|
41 |
|
|
"===== ERROR =====\n"
|
42 |
|
|
"=================\n\n");
|
43 |
|
|
break;
|
44 |
|
|
default:
|
45 |
|
|
printf("Title error.\n");
|
46 |
|
|
}
|
47 |
|
|
print_allocator_state();
|
48 |
|
|
}
|
49 |
|
|
|
50 |
|
|
void get_output_filepaths(FILE **out1, FILE **out2,
|
51 |
|
|
char *alloc_func_name)
|
52 |
|
|
{
|
53 |
|
|
char pathbuf[150];
|
54 |
|
|
char *rootpath = "/tmp/";
|
55 |
|
|
char *initstate_prefix = "test_initstate_";
|
56 |
|
|
char *endstate_prefix = "test_endstate_";
|
57 |
|
|
char *extention = ".out";
|
58 |
|
|
|
59 |
|
|
/* File path manipulations */
|
60 |
|
|
sprintf(pathbuf, "%s%s%s%s", rootpath, initstate_prefix, alloc_func_name, extention);
|
61 |
|
|
*out1 = fopen(pathbuf,"w+");
|
62 |
|
|
sprintf(pathbuf, "%s%s%s%s", rootpath, endstate_prefix, alloc_func_name, extention);
|
63 |
|
|
*out2 = fopen(pathbuf, "w+");
|
64 |
|
|
return;
|
65 |
|
|
}
|
66 |
|
|
|
67 |
|
|
/* This function is at the heart of generic random allocation testing.
|
68 |
|
|
* It is made as simple as possible, and can be used for testing all
|
69 |
|
|
* allocators. It randomly allocates/deallocates data and prints out
|
70 |
|
|
* the outcome of the action. Here are a few things it does and doesn't
|
71 |
|
|
* do:
|
72 |
|
|
* - It does not test false input on the allocators, e.g. attempting
|
73 |
|
|
* to free an address that hasn't been allocated, or attempting to
|
74 |
|
|
* free address 0.
|
75 |
|
|
* - It does capture and compare initial and final states of the
|
76 |
|
|
* allocators' internal structures after all allocations are freed.
|
77 |
|
|
* This is done by comparing two files filled with allocator state
|
78 |
|
|
* by functions supplied by the allocators themselves.
|
79 |
|
|
* - It expects the allocator NOT to run out of memory.
|
80 |
|
|
*/
|
81 |
|
|
int
|
82 |
|
|
test_alloc_free_random_order(const int MAX_ALLOCATIONS,
|
83 |
|
|
const int ALLOC_SIZE_MAX,
|
84 |
|
|
alloc_func_t alloc,
|
85 |
|
|
free_func_t free,
|
86 |
|
|
print_alloc_state_t print_allocator_state,
|
87 |
|
|
FILE *state_init_file, FILE *state_end_file)
|
88 |
|
|
{
|
89 |
|
|
/* The last element in full_state that tells about any full index.
|
90 |
|
|
* This is the limit the random deallocation would use to find a full
|
91 |
|
|
* index */
|
92 |
|
|
int random_size;
|
93 |
|
|
int random_action;
|
94 |
|
|
int random_index;
|
95 |
|
|
int alloc_so_far = 0;
|
96 |
|
|
int full_state_last = -1;
|
97 |
|
|
int halfway_through = 0;
|
98 |
|
|
FILE * const default_stdout = stdout;
|
99 |
|
|
/* Memory pointers */
|
100 |
|
|
void *mem[MAX_ALLOCATIONS];
|
101 |
|
|
/* Each element keeps track of one currently full index number */
|
102 |
|
|
int full_state[MAX_ALLOCATIONS];
|
103 |
|
|
|
104 |
|
|
/* Check arguments first */
|
105 |
|
|
if (!MAX_ALLOCATIONS || !ALLOC_SIZE_MAX || !alloc || !free
|
106 |
|
|
|| !print_allocator_state || !state_init_file || !state_end_file) {
|
107 |
|
|
printf("Invalid arguments to %s()\n", __FUNCTION__);
|
108 |
|
|
return 1;
|
109 |
|
|
}
|
110 |
|
|
memset(mem, 0, MAX_ALLOCATIONS * sizeof(void *));
|
111 |
|
|
memset(full_state, 0, MAX_ALLOCATIONS * sizeof(int));
|
112 |
|
|
|
113 |
|
|
//print_test_state(TEST_STATE_BEGIN, print_allocator_state);
|
114 |
|
|
stdout = state_init_file;
|
115 |
|
|
print_test_state(TEST_STATE_BEGIN, print_allocator_state);
|
116 |
|
|
stdout = default_stdout;
|
117 |
|
|
|
118 |
|
|
/* Randomly either allocate/deallocate at a random
|
119 |
|
|
* index, of random size */
|
120 |
|
|
srand(time(0));
|
121 |
|
|
|
122 |
|
|
while (1) {
|
123 |
|
|
if (alloc_so_far < (MAX_ALLOCATIONS / 2)) {
|
124 |
|
|
/* Give more chance to allocations at the beginning */
|
125 |
|
|
if ((rand() % 4) == 0) /* 1/4 chance */
|
126 |
|
|
random_action = FREE;
|
127 |
|
|
else /* 3/4 chance */
|
128 |
|
|
random_action = ALLOCATE;
|
129 |
|
|
} else {
|
130 |
|
|
if (!halfway_through) {
|
131 |
|
|
#if defined (DEBUG)
|
132 |
|
|
print_test_state(TEST_STATE_MIDDLE,
|
133 |
|
|
print_allocator_state);
|
134 |
|
|
#endif
|
135 |
|
|
halfway_through = 1;
|
136 |
|
|
}
|
137 |
|
|
/* Give more chane to freeing after halfway-through */
|
138 |
|
|
if ((rand() % 3) == 0) /* 1/3 chance */
|
139 |
|
|
random_action = ALLOCATE;
|
140 |
|
|
else /* 2/3 chance */
|
141 |
|
|
random_action = FREE;
|
142 |
|
|
}
|
143 |
|
|
random_size = (rand() % (ALLOC_SIZE_MAX-1)) + 1;
|
144 |
|
|
|
145 |
|
|
if (random_action == ALLOCATE) {
|
146 |
|
|
if (alloc_so_far < MAX_ALLOCATIONS) {
|
147 |
|
|
alloc_so_far++;
|
148 |
|
|
for (int i = 0; i < MAX_ALLOCATIONS; i++) {
|
149 |
|
|
if (mem[i] == 0) { // Find the first empty slot.
|
150 |
|
|
int allocation_error =
|
151 |
|
|
((mem[i] = alloc(random_size)) <= 0);
|
152 |
|
|
dprintf("%-12s%-8s%-12p%-8s%-10d\n",
|
153 |
|
|
"alloc:", "addr:", mem[i],
|
154 |
|
|
"size:", random_size);
|
155 |
|
|
if (allocation_error) {
|
156 |
|
|
print_test_state(TEST_STATE_ERROR,
|
157 |
|
|
print_allocator_state);
|
158 |
|
|
if (mem[i] < 0) {
|
159 |
|
|
printf("Error: alloc() returned negative value\n");
|
160 |
|
|
BUG();
|
161 |
|
|
} else if (mem[i] == 0) {
|
162 |
|
|
printf("Error: Allocator is out of memory.\n");
|
163 |
|
|
return 1;
|
164 |
|
|
}
|
165 |
|
|
}
|
166 |
|
|
full_state_last++;
|
167 |
|
|
full_state[full_state_last] = i;
|
168 |
|
|
break;
|
169 |
|
|
}
|
170 |
|
|
}
|
171 |
|
|
} else
|
172 |
|
|
random_action = FREE;
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
if (random_action == FREE) {
|
176 |
|
|
/* all are free, can't free anymore */
|
177 |
|
|
if (full_state_last < 0)
|
178 |
|
|
continue;
|
179 |
|
|
else if (full_state_last > 0)
|
180 |
|
|
random_index = rand() % full_state_last;
|
181 |
|
|
else
|
182 |
|
|
random_index = 0; /* Last item */
|
183 |
|
|
|
184 |
|
|
if(mem[full_state[random_index]] == 0)
|
185 |
|
|
BUG();
|
186 |
|
|
|
187 |
|
|
if (free(mem[full_state[random_index]]) < 0)
|
188 |
|
|
BUG();
|
189 |
|
|
dprintf("%-12s%-8s%-12p\n","free:",
|
190 |
|
|
"addr:", mem[full_state[random_index]]);
|
191 |
|
|
mem[full_state[random_index]] = 0;
|
192 |
|
|
|
193 |
|
|
/* Fill in the empty gap with last element */
|
194 |
|
|
full_state[random_index] = full_state[full_state_last];
|
195 |
|
|
/* Last element now in the gap
|
196 |
|
|
* (somewhere inbetween first and last) */
|
197 |
|
|
full_state[full_state_last] = 0;
|
198 |
|
|
/* One less in the number of full items */
|
199 |
|
|
full_state_last--;
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
/* Check that all allocations and deallocations took place */
|
203 |
|
|
if (alloc_so_far == MAX_ALLOCATIONS && full_state_last < 0) {
|
204 |
|
|
for (int i = 0; i < MAX_ALLOCATIONS; i++)
|
205 |
|
|
BUG_ON(full_state[i] != 0); // A final sanity check.
|
206 |
|
|
break;
|
207 |
|
|
}
|
208 |
|
|
}
|
209 |
|
|
|
210 |
|
|
//print_test_state(TEST_STATE_END, print_allocator_state);
|
211 |
|
|
stdout = state_end_file;
|
212 |
|
|
print_test_state(TEST_STATE_BEGIN, print_allocator_state);
|
213 |
|
|
stdout = default_stdout;
|
214 |
|
|
return 0;
|
215 |
|
|
}
|
216 |
|
|
|