/*
 * $Id: test_memory.c,v 1.9 2008/04/12 00:09:32 wessels Exp $
 *
 * Copyright 2006 Duane Wessels.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <inttypes.h>

#define LONGS_PER_CHUNK 1024

void progress(uint64_t, uint64_t);
void allocate(uint64_t mb);
void test(uint64_t);

uint64_t pos = 0;
time_t start;
long **chunks;
uint64_t maxi;

int
main(int argc, char *argv[])
{
    uint64_t MB;
    uint64_t pass = 0;
    start = time(NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    if (argc != 2) {
	fprintf(stderr, "usage: %s mbytes\n", argv[0]);
	return 1;
    }
    MB = atoi(argv[1]);
    assert(MB);
    allocate(MB);
    while (1)
	test(pass++);
    return 0;
}

void
allocate(uint64_t MB)
{
    uint64_t chunksize = LONGS_PER_CHUNK * sizeof(long);
    uint64_t nchunks = (MB << 20) / chunksize;
    uint64_t i = 0;
    fprintf(stderr, "allocating %"PRIu64" total bytes in %"PRIu64" chunks of %"PRIu64" bytes each\n",
	nchunks * chunksize, nchunks, chunksize);
    chunks = malloc(nchunks * sizeof(long *));
    assert(chunks);
    printf("allocate: ");
    while (i < nchunks) {
	uint64_t j;
	*(chunks + i) = malloc(chunksize);
	if (*(chunks + i) == NULL) {
	    perror("malloc");
	    break;
	}
	srandom(i + start);
	for (j = 0; j < LONGS_PER_CHUNK; j++)
	    *(*(chunks + i) + j) = random();
	progress(i, nchunks);
	maxi = ++i;
    }
    putc('.', stdout);
    putc('\n', stdout);
}

void
test(uint64_t pass)
{
    uint64_t i;
    printf("pass %0"PRIu64": ", pass);
    for (i = 0; i < maxi; i++) {
	uint64_t j;
	srandom(i + start);
	for (j = 0; j < LONGS_PER_CHUNK; j++) {
	    long e = random();
	    if (*(*(chunks + i) + j) != e) {
		fprintf(stderr, "\nERROR got %lx, expect %lx, i=%"PRIu64", j=%"PRIu64"\n",
		    *(*(chunks + i) + j), e, i, j);
	    }
	}
	progress(i, maxi);
    }
    putc('.', stdout);
    putc('\n', stdout);
}

void
progress(uint64_t i, uint64_t max)
{
    uint64_t x;
    static int swirl[4] = {'-', '\\', '|', '/'};
    if ((i & 0xFF) != 0)
	return;
    putc(swirl[(i >> 8) % 4], stdout);
    putc('\b', stdout);
    x = 68 * i / max;
    if (x == pos)
	return;
    if (x < pos) {
	pos = 0;
	return;
    }
    putc('.', stdout);
    pos = x;
}

