#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sched.h>
#include <features.h>
#include <string.h>

//#define USE_GNU
#define _GNU_SOURCE

#define	unless(x)	if (!(x))
#define	u32		unsigned int
#define	status(s)	write(1, s, 1); newline = 1;
int	newline;
void	doit(u32 bs);

int
main(int ac, char **av)
{
	//unsigned long mask;
	cpu_set_t *mask;
	int err;
	pid_t pid;
	pid = getpid();
	
	if (ac != 3) {
		printf("Usage: %s amount_in_MB cpu_to_run_on\n", av[0]);
		exit(0);
	}	

	mask = (cpu_set_t *) malloc(sizeof(cpu_set_t)); 
	if( mask == NULL ) {
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	__CPU_ZERO(mask);
	__CPU_SET(atoi(av[2]),mask);
	printf("Running on cpu: %x\n",*mask);
	err = sched_setaffinity(pid,mask);
	if( err < 0) {
		perror("sched_setaffinity:");
		exit(EXIT_FAILURE);
	}	
		
	doit(atoi(av[1])<<20);
	return (0);
}
void
bad(u32 *start, u32 *p, u32 want)
{
	u32	off = (char*)p - (char*)start;
	u32	got = *p;
	if (newline) printf("\n");
	newline = 0;
	printf("WANT=0x%08x GOT=0x%08x DIFF=0x%08x OFF=0x%08x ADDR=%p\n",
	    want, got, want - got, off, (void*)p);
}
void
doit(u32 bs)
{
	u32	*buf = malloc(bs);
	u32	*end;
	u32	*p;
	u32	off;
	fprintf(stderr, "Scrub %u bytes\n", bs);
	unless (buf) {
		perror("malloc");
		exit(1);
	}
	end = (u32*)((char*)buf + bs);
	bzero(buf, bs);
	unless (sizeof(int) == 4) {
		fprintf(stderr, "Expected 4 byte ints\n");
		exit(1);
	}
	for (off = 0, p = buf; p < end; *p++ = off, off += 4);
	for (;;) {
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != off) bad(buf, p, off);
			*p++ = 0xdeadbeef;
		}
		status("d");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0xdeadbeef) bad(buf, p, 0xdeadbeef);
			*p++ = 0x50505050;
		}
		status("5");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0x50505050) bad(buf, p, 0x50505050);
			*p++ = 0x0a0a0a0a;
		}
		status("a");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0x0a0a0a0a) bad(buf, p, 0x0a0a0a0a);
			*p++ = 0x55555555;
		}
		status("-");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0x55555555) bad(buf, p, 0x55555555);
			*p++ = 0xaaaaaaaa;
		}
		status("A");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0xaaaaaaaa) bad(buf, p, 0xaaaaaaaa);
			*p++ = 0x0;
		}
		status("0");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0x0) bad(buf, p, 0);
			*p++ = 0xffffffff;
		}
		status("f");
		for (off = 0, p = buf; p < end; off += 4) {
			if (*p != 0xffffffff) bad(buf, p, 0xffffffff);
			*p++ = off;
		}
		status("o");
	}
}
