xref: /haiku/src/tests/system/boot/heap/heapTest.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <boot/platform.h>
8 #include <boot/heap.h>
9 
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdarg.h>
14 
15 
16 extern "C" void* heap_malloc(size_t size);
17 extern "C" void* heap_realloc(void* oldBuffer, size_t size);
18 extern "C" void heap_free(void* buffer);
19 extern void dump_chunks(void);
20 extern uint32 heap_available(void);
21 
22 
23 const int32	kHeapSize = 32 * 1024;
24 
25 int32 gVerbosity = 1;
26 
27 
28 void
29 platform_release_heap(struct stage2_args* args, void* base)
30 {
31 	free(base);
32 }
33 
34 
35 status_t
36 platform_init_heap(struct stage2_args* args, void** _base, void** _top)
37 {
38 	void* base = malloc(kHeapSize);
39 	if (base == NULL)
40 		return B_NO_MEMORY;
41 
42 	*_base = base;
43 	*_top = (void*)((uint8*)base + kHeapSize);
44 
45 	return B_OK;
46 }
47 
48 
49 void
50 panic(const char* format, ...)
51 {
52 	va_list args;
53 
54 	va_start(args, format);
55 	vfprintf(stderr, format, args);
56 	va_end(args);
57 
58 	exit(-1);
59 }
60 
61 
62 void
63 dprintf(const char* format, ...)
64 {
65 	va_list args;
66 
67 	va_start(args, format);
68 	vfprintf(stdout, format, args);
69 	va_end(args);
70 }
71 
72 
73 // #pragma mark -
74 
75 
76 static void
77 dump_allocated_chunk(int32 index, void* buffer)
78 {
79 	if (buffer == NULL || gVerbosity < 3)
80 		return;
81 
82 	size_t* size = (size_t*)((uint8*)buffer - sizeof(uint32));
83 	printf("\t%ld. allocation at %p, chunk at %p, size = %ld\n", index, buffer,
84 		size, *size);
85 
86 	if (gVerbosity > 3)
87 		dump_chunks();
88 }
89 
90 
91 static void*
92 test_malloc(size_t bytes)
93 {
94 	return heap_malloc(bytes);
95 }
96 
97 
98 static void*
99 test_realloc(void* oldBuffer, size_t size)
100 {
101 	return heap_realloc(oldBuffer, size);
102 }
103 
104 
105 static void
106 test_free(void* buffer)
107 {
108 	if (gVerbosity > 4) {
109 		printf("\tfreeing buffer at %p\n", buffer);
110 		dump_allocated_chunk(-1, buffer);
111 	}
112 
113 	heap_free(buffer);
114 
115 	if (gVerbosity > 4) {
116 		puts("\t- after:");
117 		dump_chunks();
118 	}
119 }
120 
121 
122 static int32
123 random_allocations(void* array[], size_t maxSize)
124 {
125 	printf("* random allocations (up to %ld bytes)\n", maxSize);
126 
127 	size_t total = 0;
128 	int32 count = 0;
129 
130 	for (int32 i = 0; i < 100; i++) {
131 		size_t size = size_t(rand() * 1. * maxSize / RAND_MAX);
132 		array[i] = test_malloc(size);
133 		if (array[i] == NULL) {
134 			if ((size > heap_available() || size == 0) && gVerbosity < 2)
135 				continue;
136 
137 			printf(	"%ld. allocating %ld bytes failed (%ld bytes total allocated, "
138 					"%ld free (%ld))\n",
139 					i, size, total, heap_available(), kHeapSize - total);
140 		} else {
141 			dump_allocated_chunk(i, array[i]);
142 
143 			total += size;
144 			count++;
145 		}
146 	}
147 
148 	printf("\t%ld bytes allocated\n", total);
149 	if (gVerbosity > 3)
150 		dump_chunks();
151 
152 	return count;
153 }
154 
155 
156 int
157 main(int argc, char** argv)
158 {
159 	if (argc > 1)
160 		gVerbosity = atoi(argv[1]);
161 
162 	stage2_args args;
163 	memset(&args, 0, sizeof(args));
164 	args.heap_size = kHeapSize;
165 
166 	if (heap_init(&args) < B_OK) {
167 		fprintf(stderr, "Could not initialize heap.\n");
168 		return -1;
169 	}
170 
171 	printf("heap size == %ld\n", kHeapSize);
172 	if (gVerbosity > 2)
173 		dump_chunks();
174 
175 	puts("* simple allocation of 100 * 128 bytes");
176 	void* array[100];
177 	for (int32 i = 0; i < 100; i++) {
178 		array[i] = test_malloc(128);
179 		dump_allocated_chunk(i, array[i]);
180 	}
181 
182 	if (gVerbosity > 2)
183 		dump_chunks();
184 
185 	puts("* testing different deleting order");
186 	if (gVerbosity > 2)
187 		puts("- free 30 from the end (descending):");
188 
189 	for (int32 i = 100; i-- > 70; ) {
190 		test_free(array[i]);
191 		array[i] = NULL;
192 	}
193 
194 	if (gVerbosity > 2) {
195 		dump_chunks();
196 		puts("- free 40 from the middle (ascending):");
197 	}
198 
199 	for (int32 i = 30; i < 70; i++) {
200 		test_free(array[i]);
201 		array[i] = NULL;
202 	}
203 
204 	if (gVerbosity > 2) {
205 		dump_chunks();
206 		puts("- free 30 from the start (ascending):");
207 	}
208 
209 	for (int32 i = 0; i < 30; i++) {
210 		test_free(array[i]);
211 		array[i] = NULL;
212 	}
213 
214 	if (gVerbosity > 2)
215 		dump_chunks();
216 
217 	puts("* allocate until it fails");
218 	int32 i = 0;
219 	for (i = 0; i < 100; i++) {
220 		array[i] = test_malloc(kHeapSize / 64);
221 		if (array[i] == NULL) {
222 			printf("\tallocation %ld failed - could allocate %ld bytes (64th should fail).\n", i + 1, (kHeapSize / 64) * (i + 1));
223 
224 			if (gVerbosity > 2)
225 				dump_chunks();
226 
227 			while (i-- > 0) {
228 				test_free(array[i]);
229 				array[i] = NULL;
230 			}
231 
232 			break;
233 		} else
234 			dump_allocated_chunk(i, array[i]);
235 	}
236 	if (i == 100)
237 		fprintf(stderr, "could allocate more memory than in heap\n");
238 
239 	random_allocations(array, 768);
240 
241 	puts("* free memory again");
242 	for (i = 0; i < 100; i++) {
243 		test_free(array[i]);
244 		array[i] = NULL;
245 	}
246 
247 	for (size_t amount = 32; amount < 1024; amount *= 2) {
248 		int32 count = random_allocations(array, amount);
249 
250 		puts("* random freeing");
251 		while (count) {
252 			i = int32(rand() * 100. / RAND_MAX);
253 			if (array[i] == NULL)
254 				continue;
255 
256 			test_free(array[i]);
257 			array[i] = NULL;
258 			count--;
259 
260 			if (gVerbosity > 2) {
261 				puts("- freed one");
262 				dump_chunks();
263 			}
264 		}
265 	}
266 
267 	puts("* realloc() test");
268 
269 	uint8* buffer = (uint8*)test_malloc(1);
270 	buffer[0] = 'h';
271 
272 	uint8* newBuffer = (uint8*)test_realloc(buffer, 2);
273 	if (newBuffer != buffer)
274 		panic("  could not reuse buffer");
275 	newBuffer[1] = 'a';
276 	newBuffer = (uint8*)test_realloc(buffer, 3);
277 	if (newBuffer != buffer)
278 		panic("  could not reuse buffer");
279 	newBuffer[2] = 'i';
280 	newBuffer = (uint8*)test_realloc(buffer, 4);
281 	if (newBuffer != buffer)
282 		panic("  could not reuse buffer");
283 	newBuffer[3] = 'k';
284 	newBuffer = (uint8*)test_realloc(buffer, 5);
285 	if (newBuffer == buffer)
286 		panic("  could reuse buffer!");
287 	newBuffer[4] = 'u';
288 	if (memcmp(newBuffer, "haiku", 5))
289 		panic("  contents differ!");
290 
291 	heap_release(&args);
292 	return 0;
293 }
294 
295