⛏️ index : haiku.git

/*
 * Copyright 2003-2009, Axel DΓΆrfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include <util/SimpleAllocator.h>


static SimpleAllocator<> sAllocator;
const int32	kHeapSize = 32 * 1024;
int32 gVerbosity = 1;


void
panic(const char* format, ...)
{
	va_list args;

	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);

	exit(-1);
}


// #pragma mark -


static void
dump_allocated_chunk(int32 index, void* buffer)
{
	if (buffer == NULL || gVerbosity < 3)
		return;

	size_t* size = (size_t*)((uint8*)buffer - sizeof(uint32));
	printf("\t%ld. allocation at %p, chunk at %p, size = %ld\n", index, buffer,
		size, *size);

	if (gVerbosity > 3)
		sAllocator.DumpChunks();
}


static void*
test_malloc(size_t bytes)
{
	return sAllocator.Allocate(bytes);
}


static void*
test_realloc(void* oldBuffer, size_t size)
{
	return sAllocator.Reallocate(oldBuffer, size);
}


static void
test_free(void* buffer)
{
	if (gVerbosity > 4) {
		printf("\tfreeing buffer at %p\n", buffer);
		dump_allocated_chunk(-1, buffer);
	}

	sAllocator.Free(buffer);

	if (gVerbosity > 4) {
		puts("\t- after:");
		sAllocator.DumpChunks();
	}
}


static int32
random_allocations(void* array[], size_t maxSize)
{
	printf("* random allocations (up to %ld bytes)\n", maxSize);

	size_t total = 0;
	int32 count = 0;

	for (int32 i = 0; i < 100; i++) {
		size_t size = size_t(rand() * 1. * maxSize / RAND_MAX);
		array[i] = test_malloc(size);
		if (array[i] == NULL) {
			if ((size > sAllocator.Available() || size == 0) && gVerbosity < 2)
				continue;

			printf(	"%ld. allocating %ld bytes failed (%ld bytes total allocated, "
					"%ld free (%ld))\n",
					i, size, total, sAllocator.Available(), kHeapSize - total);
		} else {
			dump_allocated_chunk(i, array[i]);

			total += size;
			count++;
		}
	}

	printf("\t%ld bytes allocated\n", total);
	if (gVerbosity > 3)
		sAllocator.DumpChunks();

	return count;
}


int
main(int argc, char** argv)
{
	if (argc > 1)
		gVerbosity = atoi(argv[1]);

	void* base = malloc(kHeapSize);
	if (base == NULL) {
		fprintf(stderr, "Could not initialize heap.\n");
		return -1;
	}
	sAllocator.AddChunk(base, kHeapSize);

	printf("heap size == %" B_PRId32 "\n", kHeapSize);
	if (gVerbosity > 2)
		sAllocator.DumpChunks();

	puts("* simple allocation of 100 * 128 bytes");
	void* array[100];
	for (int32 i = 0; i < 100; i++) {
		array[i] = test_malloc(128);
		dump_allocated_chunk(i, array[i]);
	}

	if (gVerbosity > 2)
		sAllocator.DumpChunks();

	puts("* testing different deleting order");
	if (gVerbosity > 2)
		puts("- free 30 from the end (descending):");

	for (int32 i = 100; i-- > 70; ) {
		test_free(array[i]);
		array[i] = NULL;
	}

	if (gVerbosity > 2) {
		sAllocator.DumpChunks();
		puts("- free 40 from the middle (ascending):");
	}

	for (int32 i = 30; i < 70; i++) {
		test_free(array[i]);
		array[i] = NULL;
	}

	if (gVerbosity > 2) {
		sAllocator.DumpChunks();
		puts("- free 30 from the start (ascending):");
	}

	for (int32 i = 0; i < 30; i++) {
		test_free(array[i]);
		array[i] = NULL;
	}

	if (gVerbosity > 2)
		sAllocator.DumpChunks();

	puts("* allocate until it fails");
	int32 i = 0;
	for (i = 0; i < 100; i++) {
		array[i] = test_malloc(kHeapSize / 64);
		if (array[i] == NULL) {
			printf("\tallocation %ld failed - could allocate %" B_PRId32 " bytes (64th should fail).\n", i + 1, (kHeapSize / 64) * (i + 1));

			if (gVerbosity > 2)
				sAllocator.DumpChunks();

			while (i-- > 0) {
				test_free(array[i]);
				array[i] = NULL;
			}

			break;
		} else
			dump_allocated_chunk(i, array[i]);
	}
	if (i == 100)
		fprintf(stderr, "could allocate more memory than in heap\n");

	random_allocations(array, 768);

	puts("* free memory again");
	for (i = 0; i < 100; i++) {
		test_free(array[i]);
		array[i] = NULL;
	}

	for (size_t amount = 32; amount < 1024; amount *= 2) {
		int32 count = random_allocations(array, amount);

		puts("* random freeing");
		while (count) {
			i = int32(rand() * 100. / RAND_MAX);
			if (array[i] == NULL)
				continue;

			test_free(array[i]);
			array[i] = NULL;
			count--;

			if (gVerbosity > 2) {
				puts("- freed one");
				sAllocator.DumpChunks();
			}
		}
	}

	puts("* realloc() test");

	uint8* buffer = (uint8*)test_malloc(1);
	buffer[0] = 'h';

	uint8* newBuffer = (uint8*)test_realloc(buffer, 2);
	if (newBuffer != buffer)
		panic("  could not reuse buffer");
	newBuffer[1] = 'a';
	newBuffer = (uint8*)test_realloc(buffer, 3);
	if (newBuffer != buffer)
		panic("  could not reuse buffer");
	newBuffer[2] = 'i';
	newBuffer = (uint8*)test_realloc(buffer, 4);
	if (newBuffer != buffer)
		panic("  could not reuse buffer");
	newBuffer[3] = 'k';
	newBuffer = (uint8*)test_realloc(buffer, 5);
	if (newBuffer == buffer)
		panic("  could reuse buffer!");
	newBuffer[4] = 'u';
	if (memcmp(newBuffer, "haiku", 5))
		panic("  contents differ!");

	free(base);
	return 0;
}