205 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * bloat - waste memory.
 | 
						|
 *
 | 
						|
 * This test allocates memory a page at a time and keeps going until
 | 
						|
 * it runs out. It gets the memory directly with sbrk to avoid malloc-
 | 
						|
 * related overheads, which as long as OS/161 has a dumb userlevel
 | 
						|
 * malloc is important for performance.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdbool.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <err.h>
 | 
						|
 | 
						|
/* OS/161 doesn't currently have a way to get this from the kernel. */
 | 
						|
#define PAGE_SIZE 4096
 | 
						|
 | 
						|
/* the memory we've gotten */
 | 
						|
static void *firstpage;
 | 
						|
static void *lastpage;
 | 
						|
 | 
						|
/* number of page allocations per cycle */
 | 
						|
static unsigned allocs;
 | 
						|
 | 
						|
/* number of pages to touch every cycle */
 | 
						|
static unsigned touchpages;
 | 
						|
 | 
						|
/* when touching pages, the extent to which we favor the middle of the range */
 | 
						|
static unsigned bias;
 | 
						|
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
moremem(void)
 | 
						|
{
 | 
						|
	static unsigned totalpages;
 | 
						|
 | 
						|
	void *ptr;
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	for (i=0; i<allocs; i++) {
 | 
						|
		ptr = sbrk(PAGE_SIZE);
 | 
						|
		if (ptr == (void *)-1) {
 | 
						|
			err(1, "After %u pages: sbrk", totalpages);
 | 
						|
		}
 | 
						|
		totalpages++;
 | 
						|
		lastpage = ptr;
 | 
						|
		if (firstpage == NULL) {
 | 
						|
			firstpage = ptr;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
touchpage(unsigned pagenum)
 | 
						|
{
 | 
						|
	int *ptr;
 | 
						|
 | 
						|
	ptr = (void *)((uintptr_t)firstpage + PAGE_SIZE * pagenum);
 | 
						|
	*ptr = pagenum;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
unsigned
 | 
						|
pickpage(unsigned numpages)
 | 
						|
{
 | 
						|
	unsigned mnum, moffset;
 | 
						|
	unsigned span, val, i;
 | 
						|
 | 
						|
	/* take 1 in 1000 pages uniformly from the entire space */
 | 
						|
	if (random() % 1000 == 0) {
 | 
						|
		return random() % numpages;
 | 
						|
	}
 | 
						|
 | 
						|
	/* the rest is taken from the middle 1% */
 | 
						|
 | 
						|
	mnum = numpages / 100;
 | 
						|
	if (mnum < touchpages * 2) {
 | 
						|
		mnum = touchpages * 2;
 | 
						|
	}
 | 
						|
	if (mnum >= numpages) {
 | 
						|
		mnum = numpages;
 | 
						|
	}
 | 
						|
	moffset = numpages / 2 - mnum / 2;
 | 
						|
 | 
						|
	assert(bias >= 1);
 | 
						|
	span = (mnum + bias - 1) / bias;
 | 
						|
 | 
						|
	do {
 | 
						|
		val = 0;
 | 
						|
		for (i=0; i<bias; i++) {
 | 
						|
			val += random() % span;
 | 
						|
		}
 | 
						|
	} while (val >= mnum);
 | 
						|
	return moffset + val;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
touchmem(void)
 | 
						|
{
 | 
						|
	unsigned i, num;
 | 
						|
 | 
						|
	num = (((uintptr_t)lastpage - (uintptr_t)firstpage) / PAGE_SIZE) + 1;
 | 
						|
 | 
						|
	if (num % 256 == 0) {
 | 
						|
		warnx("%u pages", num);
 | 
						|
	}
 | 
						|
 | 
						|
	for (i=0; i<touchpages; i++) {
 | 
						|
		touchpage(pickpage(num));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
run(void)
 | 
						|
{
 | 
						|
	while (1) {
 | 
						|
		moremem();
 | 
						|
		touchmem();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
printsettings(void)
 | 
						|
{
 | 
						|
	tprintf("Page size: %u\n", PAGE_SIZE);
 | 
						|
	tprintf("Allocating %u pages and touching %u pages on each cycle.\n",
 | 
						|
	       allocs, touchpages);
 | 
						|
	tprintf("Page selection bias: %u\n", bias);
 | 
						|
	tprintf("\n");
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
usage(void)
 | 
						|
{
 | 
						|
	warnx("bloat [-a allocs] [-b bias] [-p pages]");
 | 
						|
	warnx("   allocs: number of pages allocated per cycle (default 4)");
 | 
						|
	warnx("   bias: number of dice rolled to touch pages (default 8)");
 | 
						|
	warnx("   pages: pages touched per cycle (default 8)");
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char *argv[])
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	/* default mode */
 | 
						|
	allocs = 4;
 | 
						|
	touchpages = 8;
 | 
						|
	bias = 8;
 | 
						|
 | 
						|
	srandom(1234);
 | 
						|
 | 
						|
	for (i=1; i<argc; i++) {
 | 
						|
		if (!strcmp(argv[i], "-a")) {
 | 
						|
			i++;
 | 
						|
			if (i == argc) {
 | 
						|
				errx(1, "-a: option requires argument");
 | 
						|
			}
 | 
						|
			allocs = atoi(argv[i]);
 | 
						|
			if (allocs == 0) {
 | 
						|
				errx(1, "-a: must not be zero");
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(argv[i], "-b")) {
 | 
						|
			i++;
 | 
						|
			if (i == argc) {
 | 
						|
				errx(1, "-b: option requires argument");
 | 
						|
			}
 | 
						|
			bias = atoi(argv[i]);
 | 
						|
			if (bias == 0) {
 | 
						|
				errx(1, "-b: must not be zero");
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(argv[i], "-h")) {
 | 
						|
			usage();
 | 
						|
		}
 | 
						|
		else if (!strcmp(argv[i], "-p")) {
 | 
						|
			i++;
 | 
						|
			if (i == argc) {
 | 
						|
				errx(1, "-p: option requires argument");
 | 
						|
			}
 | 
						|
			touchpages = atoi(argv[i]);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			errx(1, "Argument %s not recognized", argv[i]);
 | 
						|
			usage();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	printsettings();
 | 
						|
	run();
 | 
						|
	return 0;
 | 
						|
}
 |